Subscribe

Category: PHP

It’s fairly easy to construct a filename that refers to something other than what you intended. For example, say you have a $username variable that contains the name the user wants to be called, which the user has specified through a form field. Now let’s say you want to store a welcome message for each user in the directory /usr/local/lib/ greetings so that you can output the message any time the user logs in to your application.

The code to print the current user’s greeting is:

PHP

1

include("/usr/local/lib/greetings/{$username}");

This seems harmless enough, but what if the user chose the username ” ../../../../etc/passwd“? The code to include the greeting now includes this relative path instead: /etc/passwd. Relative paths are a common trick used by hackers against unsuspecting scripts.

Another trap for the unwary programmer lies in the way that, by default, PHP can open remote files with the same functions that open local files. The fopen() function and anything that uses it (e.g., include() and require()) can be passed an HTTP or FTP URL as a filename, and the document identified by the URL will be opened. For example:

PHP

1

2

3

chdir("/usr/local/lib/greetings");

$fp=fopen($username,'r');

If $username is set to http://www.example.com/myfile, a remote file is opened, not a local one.

The situation is even worse if you let the user tell you which file to include():

PHP

1

2

3

$file=$_REQUEST['theme'];

include($file);

If the user passes a theme parameter of http://www.example.com/badcode.inc and your variables_order includes GET or POST, your PHP script will happily load and run the remote code. Never use parameters as filenames like this.

There are several solutions to the problem of checking filenames. You can disable remote file access, check filenames with realpath() and basename(), and use the open_basedir option to restrict filesystem access outside your site’s document root.

Check for relative paths

When you need to allow the user to specify a filename in your application, you can use a combination of the realpath() and basename() functions to ensure that the filename is what it ought to be. The realpath() function resolves special markers such as .and … After a call to realpath(), the resulting path is a full path on which you can then use basename(). The basename() function returns just the filename portion of the path.

Going back to our welcome message scenario, here’s an example of realpath() and basename() in action:

PHP

1

2

3

4

5

6

$filename=$_POST['username'];

$vetted=basename(realpath($filename));

if($filename!==$vetted){

die("{$filename} is not a good username");

}

In this case, we’ve resolved $filename to its full path and then extracted just the filename. If this value doesn’t match the original value of $filename, we’ve got a bad filename that we don’t want to use.

Once you have the completely bare filename, you can reconstruct what the file path ought to be, based on where legal files should go, and add a file extension based on the actual contents of the file:

Escaping is a technique that preserves data as it enters another context. PHP is frequently used as a bridge between disparate data sources, and when you send data to a remote source, it’s your responsibility to prepare it properly so that it’s not misinterpreted.

For example, O’Reilly is represented as O\’Reilly when used in an SQL query to be sent to a MySQL database. The backslash before the single quote exists to preserve the single quote in the context of the SQL query. The single quote is part of the data, not part of the query, and the escaping guarantees this interpretation.

The two predominant remote sources to which PHP applications send data are HTTP clients (web browsers) that interpret HTML, JavaScript, and other client-side technologies, and databases that interpret SQL. For the former, PHP provides htmlentities():

This example demonstrates the use of another naming convention. The $html array is similar to the $clean array, except that its purpose is to hold data that is safe to be used in the context of HTML.

URLs are sometimes embedded in HTML as links:

1

<ahref="http://host/script.php?var={$value}">Click Here</a>

In this particular example, $value exists within nested contexts. It’s within the query string of a URL that is embedded in HTML as a link. Because it’s alphabetic in this case, it’s safe to be used in both contexts. However, when the value of $var cannot be guaranteed to be safe in these contexts, it must be escaped twice:

PHP

1

2

3

4

5

6

7

8

9

10

$url=array(

'value'=>urlencode($value),

);

$link="http://host/script.php?var={$url['value']}";

$html=array(

'link'=>htmlentities($link,ENT_QUOTES,'UTF-8'),

);

echo"<a href=\"{$html['link']}\">Click Here</a>";

This ensures that the link is safe to be used in the context of HTML, and when it is used as a URL (such as when the user clicks the link), the URL encoding ensures that the value of $var is preserved.

For most databases, there is a native escaping function specific to the database. For example, the MySQL extension provides mysqli_real_escape_string():

PHP

1

2

3

4

5

6

7

8

$mysql=array(

'username'=>mysqli_real_escape_string($clean['username']),

);

$sql="SELECT * FROM profile

WHERE username = '{$mysql['username']}'";

$result=mysql_query($sql);

An even safer alternative is to use a database abstraction library that handles the escaping for you. The following illustrates this concept with PEAR::DB:

1

2

3

$sql="INSERT INTO users (last_name) VALUES (?)";

$db->query($sql,array($clean['last_name']));

Although this is not a complete example, it highlights the use of a placeholder (the question mark) in the SQL query. PEAR::DB properly quotes and escapes the data according to the requirements of your database.

A more complete output-escaping solution would include context-aware escaping for HTML elements, HTML attributes, JavaScript, CSS, and URL content, and would do so in a Unicode-safe manner. Here in Example, is a sample class for escaping output in a variety of contexts, based on the content-escaping rules defined by the Open Web Application Security Project.

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

classEncoder

{

constENCODE_STYLE_HTML=0;

constENCODE_STYLE_JAVASCRIPT=1;

constENCODE_STYLE_CSS=2;

constENCODE_STYLE_URL=3;

constENCODE_STYLE_URL_SPECIAL=4;

privatestatic$URL_UNRESERVED_CHARS=

'ABCDEFGHIJKLMNOPQRSTUVWXYZabcedfghijklmnopqrstuvwxyz-_.~';

publicfunctionencodeForHTML($value)

{

$value=str_replace('&','&amp;',$value);

$value=str_replace('<','&lt;',$value);

$value=str_replace('>','&gt;',$value);

$value=str_replace('"','&quot;',$value);

$value=str_replace('\'','&#x27;',$value);// &apos; is not recommended

$value=str_replace('/','&#x2F;',$value);// forward slash can help end HTML entity

return$value;

}

publicfunctionencodeForHTMLAttribute($value)

{

return$this->_encodeString($value);

}

publicfunctionencodeForJavascript($value)

{

return$this->_encodeString($value,self::ENCODE_STYLE_JAVASCRIPT);

}

publicfunctionencodeForURL($value)

{

return$this->_encodeString($value,self::ENCODE_STYLE_URL_SPECIAL);

}

publicfunctionencodeForCSS($value)

{

return$this->_encodeString($value,self::ENCODE_STYLE_CSS);

}

/**

* Encodes any special characters in the path portion of the URL. Does not

* modify the forward slash used to denote directories. If your directory

* names contain slashes (rare), use the plain urlencode on each directory

The second most common web application vulnerability is SQL injection, an attack very similar to XSS. The difference is that SQL injection vulnerabilities exist wherever you use un-escaped data in an SQL query. (If these names were more consistent, XSS would probably be called HTML injection.)

The following example demonstrates an SQL injection vulnerability:

PHP

1

2

3

4

5

6

$hash=hash($_POST['password']);

$sql="SELECT count(*) FROM users

WHERE username = '{$_POST['username']}' AND password = '{$hash}'";

$result=mysql_query($sql);

The problem is that without escaping the username, its value can manipulate the format of the SQL query. Because this particular vulnerability is so common, many attackers try usernames such as the following when trying to log in to a target site:

1

chris'--

I often joke that this is my favorite username, because it allows access to the account with the username chris’ without me having to know that account’s password. After interpolation, the SQL query becomes:

MySQL

1

2

3

4

SELECT count(*)

FROMusers

WHEREusername='chris'--'

AND password = '...'";

Because two consecutive hyphens (–) indicate the beginning of an SQL comment, this query is identical to:

MySQL

1

2

3

SELECT count(*)

FROMusers

WHEREusername='chris'

If the code containing this snippet of code assumes a successful login when $result is nonzero, this SQL injection would allow an attacker to log in to any account without having to know or guess the password.

However, this only assures that the data you escape is interpreted as data. You still need to filter data, because characters like the percent sign (%) have a special meaning in SQL but they don’t need to be escaped.

The best protection against SQL injection is the use of bound parameters. The following example demonstrates the use of bound parameters with PHP’s PDO extension and an Oracle database:

Because bound parameters ensure that the data never enters a context where it can be considered anything but data (i.e., it’s never misinterpreted), no escaping of the username and password is necessary.
Here is the list of of Article in this Series:

Previous in this series we learn how to securely filter the input and store in the database. Here I will let you know how prevent Cross-Site Scripting.

What is Cross-Site Scripting?

Cross-site scripting (XSS) has become the most common web application security vulnerability, and with the rising popularity of Ajax technologies, XSS attacks are likely to become more advanced and to occur more frequently.

The term cross-site scripting derives from an old exploit and is no longer very descriptive or accurate for most modern attacks, and this has caused some confusion.

Simply put, your code is vulnerable whenever you output data not properly escaped to the output’s context. For example:

PHP

1

echo$_POST['username'];

This is an extreme example, because $_POST is obviously neither filtered nor escaped, but it demonstrates the vulnerability.

XSS attacks are limited to only what is possible with client-side technologies. Historically, XSS has been used to capture a victim’s cookies by taking advantage of the fact that document.cookie contains this information.

Preventing XSS

In order to prevent XSS, you simply need to properly escape your output for the output context:

PHP

1

2

3

4

5

$html=array(

'username'=>htmlentities($_POST['username'],ENT_QUOTES,'UTF-8'),

);

echo$html['username'];

You should also always filter your input, and filtering can offer a redundant safeguard in some cases (implementing redundant safeguards adheres to a security principle known as Defense in Depth). For example, if you inspect a username to ensure it’s alphabetic and also only output the filtered username, no XSS vulnerability exists.

Just be sure that you don’t depend upon filtering as your primary safeguard against XSS, because it doesn’t address the root cause of the problem.

Previously in this series we see why security is important for PHP web application and extension we develop for various CMS. In this article we we learn how we can filter the input from user and securely use the input.

One of the most fundamental things to understand when developing a secure site is this: all information not generated within the application itself is potentially tainted. This includes data from forms, files, and databases.

When data is described as being tainted, this doesn’t mean it’s necessarily malicious. It means it might be malicious. You can’t trust the source, so you should inspect it to make sure it’s valid. This inspection process is called filtering, and you only want to allow valid data to enter your application.

There are a few best practices regarding the filtering process:

Use a whitelist approach. This means you err on the side of caution and assume data to be invalid unless you can prove it to be valid.

Never correct invalid data. History has proven that attempts to correct invalid data often result in security vulnerabilities due to errors.

Use a naming convention to help distinguish between filtered and tainted data. Filtering is useless if you can’t reliably determine whether something has been filtered.

In order to solidify these concepts, consider a simple HTML form allowing a user to select among three colors:

PHP

1

2

3

4

5

6

7

8

9

10

11

<form action="process.php"method="POST">

<p>Please selectacolor:

<select name="color">

<option value="red">red</option>

<option value="green">green</option>

<option value="blue">blue</option>

</select>

<input type="submit"/></p>

</form>

It’s easy to appreciate the desire to trust $_POST['color'] in process.php. After all, the form seemingly restricts what a user can enter. However, experienced developers know HTTP requests have no restriction on the fields they contain—client-side validation is never sufficient by itself. There are numerous ways malicious data can be sent to your application, and your only defense is to trust nothing and filter your input:

PHP

1

2

3

4

5

6

7

8

9

10

11

12

$clean=array();

switch($_POST['color']){

case'red':

case'green':

case'blue':

$clean['color']=$_POST['color'];

break;

default:

/* ERROR */

break;

}

This example demonstrates a simple naming convention. You initialize an array called $clean. For each input field, validate the input and store the validated input into the array. This reduces the likelihood of tainted data being mistaken for filtered data, because you should always err on the side of caution and consider everything not stored in this array to be tainted.

Your filtering logic depends entirely upon the type of data you’re inspecting, and the more restrictive you can be, the better. For example, consider a registration form that asks the user to provide a desired username. Clearly, there are many possible usernames, so the previous example doesn’t help. In these cases, the best approach is to filter based on format. If you want to require a username to be alphanumeric (consisting of only alphabetic and numeric characters), your filtering logic can enforce this:

PHP

1

2

3

4

5

6

7

8

$clean=array();

if(ctype_alnum($_POST['username'])){

$clean['username']=$_POST['username'];

}

else{

/* ERROR */

}

Of course, this doesn’t ensure any particular length. Use mb_strlen() to inspect a string’s length and enforce a minimum and maximum:

PHP

1

2

3

4

5

6

7

8

9

10

$clean=array();

$length=mb_strlen($_POST['username']);

if(ctype_alnum($_POST['username'])&&($length>0)&&($length<=32)){

$clean['username']=$_POST['username'];

}

else{

/* ERROR */

}

Frequently, the characters you want to allow don’t all belong to a single group (such as alphanumeric), and this is where regular expressions can help. For example, consider the following filtering logic for a last name:

PHP

1

2

3

4

5

6

7

8

$clean=array();

if(preg_match('/[^A-Za-z \'\-]/',$_POST['last_name'])){

/* ERROR */

}

else{

$clean['last_name']=$_POST['last_name'];

}

This only allows alphabetic characters, spaces, hyphens, and single quotes (apostrophes), and it uses a whitelist approach as described earlier. In this case, the whitelist is the list of valid characters.

In general, filtering is a process that ensures the integrity of your data. Although filtering alone can prevent many web application security vulnerabilities, most are due to a failure to escape data, and neither is a substitute for the other.

With increasing use of PHP language, It is very important to develop code with no security problems. Now a days, PHP language is used many application and CMSs like WordPress, Magento, OpenCart, Drupal, Joomla etc. These all CMSs provide is own security. But problem is when we create custom plugins and extension to extends the features of CMS. Developer needs to take care of many security threats and make code very with security provided. Here I will show many security threats in PHP code and How to overcome of these security threats.

PHP is a flexible language with hooks into just about every API offered on the machines on which it runs. Because it was designed to be a forms-processing language for HTML pages, PHP makes it easy to use form data sent to a script. Convenience is a doubleedged sword, however. The very features that allow you to quickly write programs in PHP can open doors for those who would break into your systems.

PHP itself is neither secure nor insecure. The security of your web applications is entirely determined by the code you write. For example, if a script opens a file whose name is passed to the script as a form parameter, that script could be given a remote URL, an absolute pathname, or even a relative path, allowing it to open a file outside the site’s document root. This could expose your password file or other sensitive information.

This series of tutorial takes a pragmatic approach and covers a distilled selection of topics related to security, including how to protect your applications from the most common and dangerous attacks. Here is the list what I am going to cover in these series.

If only you and people you trust can log in to your web server, you don’t need to worry about file permissions for files used by or created by your PHP programs. However, most websites are hosted on ISP’s machines, and there’s a risk that non trusted people can read files that your PHP program creates. There are a number of techniques that you can use to deal with file permissions issues.

Restrict Filesystem Access to a Specific Directory You can set the open_basedir option to restrict access from your PHP scripts to a specific directory. If open_basedir is set in your php.ini, PHP limits filesystem and I/O functions so that they can operate only within that directory or any of its subdirectories. For example:

1

open_basedir=/some/path

With this configuration in effect, the following function calls succeed:

PHP

1

2

3

unlink("/some/path/unwanted.exe");

include("/some/path/less/travelled.inc");

But these generate runtime errors:

PHP

1

2

3

$fp=fopen("/some/other/file.exe",'r');

$dp=opendir("/some/path/../other/file.exe");

Of course, one web server can run many applications, and each application typically stores files in its own directory. You can configure open_basedir on a per-virtual host basis in your httpd.conf file like this:

1

2

3

4

5

<VirtualHost1.2.3.4>

ServerName domainA.com

DocumentRoot/web/sites/domainA

php_admin_value open_basedir/web/sites/domainA

</VirtualHost>

Similarly, you can configure it per directory or per URL in httpd.conf:

1

2

3

4

5

6

7

8

9

10

11

# by directory

<Directory/home/httpd/html/app1>

php_admin_value open_basedir/home/httpd/html/app1

</Directory>

# by URL

<Location/app2>

php_admin_value open_basedir/home/httpd/html/app2

</Location>

The open_basedir directory can be set only in the httpd.conf file, not in .htaccess files, and you must use php_admin_value to set it.

Get It Right the First Time

Do not create a file and then change its permissions. This creates a race condition, where a lucky user can open the file once it’s created but before it’s locked down. Instead, use the umask() function to strip off unnecessary permissions. For example:

1

2

3

umask(077);// disable ---rwxrwx

$fh=fopen("/tmp/myfile",'w');

By default, the fopen() function attempts to create a file with permission 0666 (rw-rwrw-). Calling umask() first disables the group and other bits, leaving only 0600 (rw-------). Now, when fopen() is called, the file is created with those permissions.

Don’t Use Files

Because all scripts running on a machine run as the same user, a file that one script creates can be read by another, regardless of which user wrote the script. All a script needs to know to read a file is the name of that file.

There is no way to change this, so the best solution is to not use files to store data that should be protected; the most secure place to store data is in a database.

A complex workaround is to run a separate Apache daemon for each user. If you add a reverse proxy such as haproxy in front of the pool of Apache instances, you may be able to serve 100+ users on a single machine. Few sites do this, however, because the complexity and cost are much greater than those for the typical situation, where one Apache daemon can serve web pages for thousands of users.

Session Files

With PHP’s built-in session support, session information is stored in files. Each file is named /tmp/sess_id, where id is the name of the session and is owned by the web server user ID, usually nobody.

Because all PHP scripts run as the same user through the web server, this means that any PHP script hosted on a server can read any session files for any other PHP site. In situations where your PHP code is stored on an ISP’s server that is shared with other users’ PHP scripts, variables you store in your sessions are visible to other PHP scripts.

Even worse, other users on the server can create files in the session directory /tmp. There’s nothing preventing a user from creating a fake session file that has any variables and values he wants in it. The user can then have the browser send your script a cookie containing the name of the faked session, and your script will happily load the variables stored in the fake session file.

One workaround is to ask your service provider to configure their server to place your session files in your own directory. Typically, this means that your VirtualHost block in the Apache httpd.conf file will contain:

1

php_value session.save_path/some/path

If you have .htaccess capabilities on your server and Apache is configured to let you override options, you can make the change yourself.

Concealing PHP Libraries

Many a hacker has learned of weaknesses by downloading include files or data that are stored alongside HTML and PHP files in the web server’s document root. To prevent this from happening to you, all you need to do is store code libraries and data outside the server’s document root.

For example, if the document root is /home/httpd/html, everything below that directory can be downloaded through a URL. It is a simple matter to put your library code, configuration files, logfiles, and other data outside that directory (e.g., in /usr/local/lib/myapp). This doesn’t prevent other users on the web server from accessing those files but it does prevent the files from being downloaded by remote users.

If you must store these auxiliary files in your document root, you should configure the web server to deny requests for those files. For example, this tells Apache to deny requests for any file with the .inc extension, a common extension for PHP include files:

1

2

3

4

<Files~"\.inc$">

Order allow,deny

Deny from all

</Files>

A better and more preferred way to prevent downloading of PHP source files is to always use the .php extension.

If you store code libraries in a different directory from the PHP pages that use them, you’ll need to tell PHP where the libraries are. Either give a path to the code in each include() or require(), or change include_path in php.ini:

Today, with increasing of high resolution devices, Client ask developer to add retina image support to their theme. Support Retina is to display high quality image on high resolution devices. This means we need to create high resolution images and to load right images based on screen resolutions.

There are some plugins available on WordPress for regular users to add retina display images. Searching a wordpress directory for plugin shows below 5 plugins on top

Each plugin show use different way to show retina images but internal all includes two things, A detection script and a retina-ready image creation function. For developer who want to include the feature of displaying retina image to their theme, It very first step to select right JavaScript to detect the screen resolution and display the image.

Detect Screen Display

We need to display high quality image if user device is supporting it. The best way to detect a screen is using JavaScript. I generally use a script called retina.js by Imulus. Its size is only 4kb and includes all the front-end functionality you need to detect a retina display and load the right image.

Copy retina.js file to your theme /js folder. It should be in right place to enqueue the script correctly.

Above code is enough to detect the screen display. Now we have to create function to create high quality image.

High Quality Image Creation

We need to add a function such that each time image is uploaded or added a high resolution image is created automatically and stored with @2x added to the filename. The detection JavaScript will search for @2x suffix in filename to load the retina-ready version of the image if required.

In order to make sure that a retina-ready image is created automatically whenever an image is uploaded, you need to hook into the appropriate WordPress filter. The correct one to use is wp_generate_attachment_metadata.

By this function, new retina image will be created with suffix @2x added to the name. Now detection script will work with these new image.

That’s all you need to do to make it work, but adding one extra function will help in reducing the usage of server bytes. This function is for deleting the image that we have created for retina display when original image is deleted.

Now a days many Websites and Web application are using WordPress as their back-end. With increasing users of WordPress requires many more functionality to implement. Many Web Application / Websites requires to redirect users based on User’s role to particular or custom page.

Today Here I will let you know how can we implement to redirect user by user’s role in your WordPress Website. We will use hook “wp_login” and add one function to check current user role and then based on role we will redirect the user to predefined page (Custom Page).

To implement this you need to create one plugin and add below code to that

Last few day I was searching for the layered search using MySQL. Layered Search is actually a Faceted Search. (Magento, a highly professional e-commerce platform on php name it Layered Search). Faceted Search can be done using two way MySQL/Any DB Application or using Apache Solr.

In this post I will show you how we can do Faceted search using MySQL database. You need a specific database schema, but it’s feasible. Here’s a simple example:

product Table

1

2

3

4

5

6

+----+------------+

|id|name|

+----+------------+

|1|blue paint|

|2|red paint|

+----+------------+

classification Table

1

2

3

4

5

6

7

+----+----------+

|id|name|

+----+----------+

|1|color|

|2|material|

|3|dept|

+----+----------+

product_classification Table

1

2

3

4

5

6

7

8

9

10

11

12

+------------+-------------------+-------+

|product_id|classification_id|value|

+------------+-------------------+-------+

|1|1|blue|

|1|2|latex|

|1|3|paint|

|1|3|home|

|2|1|red|

|2|2|latex|

|2|3|paint|

|2|3|home|

+------------+-------------------+-------+

So, say someones search for paint, you’d do something like:

1

SELECTp.*FROM productpWHERE name LIKE'%paint%';

This would return both entries from the product table.

Once your search has executed, you can fetch the associated facets (filters) of your result using a query like this one:

1

2

3

4

5

6

SELECTc.id,c.name,pc.value FROM productp

LEFT JOIN product_classification pc ON pc.product_id=p.id

LEFT JOIN classificationcONc.id=pc.classification_id

WHEREp.name LIKE'%paint%'

GROUP BYc.id,pc.value

ORDER BYc.id;

This’ll give you something like:

1

2

3

4

5

6

7

8

9

+------+----------+-------+

|id|name|value|

+------+----------+-------+

|1|color|blue|

|1|color|red|

|2|material|latex|

|3|dept|home|

|3|dept|paint|

+------+----------+-------+

So, in your result set, you know that there are products whose color are blue and red, that the only material it’s made from is latex, and that it can be found in departments home and paint.

Once a user select a facet, just modify the original search query:

1

2

3

4

5

6

7

8

9

SELECTp.*FROM productp

LEFT JOIN product_classification pc ON pc.product_id=p.id

WHERE

p.name LIKE'%paint%'AND(

(pc.classification_id=1ANDpc.value='blue')OR

(pc.classification_id=3ANDpc.value='home')

)

GROUP BYp.id

HAVING COUNT(p.id)=2;

So, here the user is searching for keyword paint, and includes two facets: facet blue for color, andhome for department. This’ll give you:

1

2

3

4

5

+----+------------+

|id|name|

+----+------------+

|1|blue paint|

+----+------------+

So, in conclusion. Although it’s available out-of-the-box in Solr, it’s possible to implement it in SQL fairly easily.