When it comes to application security, in addition to securing your
hardware and platform, you also need to write your code securely. This
article will explain how to keep your application secure and less
vulnerable to hacking. The following are the best habits that a
programmer can develop in order to protect his or her application from
attack:
- Input data validation
- Guarding against XSS attacks
- Guarding against CSRF attacks
- Preventing SQL Injection attacks
- Protecting the file system
- Protecting session data
- Proper error handling
- Guarding included files
Input Data Validation
While designing your application, you should be striving to guard your app against bad input. The rule of thumb to follow is this: don’t trust user input. Although your app is intended for good people, there is always a chance that some bad user will try to attack your app by entering bad input. If you always validate and filter the incoming data, you can build a secure application.Always validate data in your PHP code. If you are using JavaScript to validate user input, there is always a chance that the user might have turned off JavaScript in her browser. In this case your app will not be able to validate the input. Validating in JavaScript is okay, but to guard against these types of problems then you should re-validate the data in PHP as well too.
Guarding Against XSS Attacks
Cross-site scripting attack (XSS attack) is an attack based on code injection into vulnerable web pages. The danger is a result of accepting unchecked input data and showing it in the browser.Suppose you have a comment form in your application that allows users to enter data, and on successful submission it shows all the comments. The user could possibly enter a comment that contains malicious JavaScript code in it. When the form is submitted, the data is sent to the server and stored into the database. Afterward, the comment is fetched from database and shown in the HTML page and the JavaScript code will run. The malicious JavaScript might redirect the user to a bad web page or a phishing website.
To protect your application from these kinds of attacks, run the input data through
strip_tags()
to remove any tags present in it. When showing data in the browser, apply htmlentities()
function on the data.Guarding Against CSRF Attacks
In a Cross Site Request Forgery (CSRF) attack, the attacker tricks the victim into loading sensitive information or making a transaction without their knowledge. This mainly occurs in web applications that are badly coded to trigger business logic using GET requests.Ideally, GET requests are Idempotent in nature. Idempotency means the same page can be accessed multiple times without causing any side effects. Therefore, GET requests should be used only for accessing information and not for performing transactions.
The following example shows a how a poorly coded application unknowingly supports CSRF attacks:
<?php
if
(isset(
$_REQUEST
[
"name"
],
$_REQUEST
[
"amount"
])) {
// process the request and transfer the amount from
// from the logged in user to the passed name.
}?>
<
a
href
=
"http://example.com/process.php?name=Bob&amount=1000"
>Visit My WebSite</
a
>
If Alice clicks on this link, and is logged into the website already,
this request will deduct $1000 from her account and transfer it to
Bob’s! Alternatively, Bob can create an image link whose src attribute
points to the URL.
<
img
src
=
"http://example.com/process.php?name=Bob&amount=1000"
width
=
"1"
height
=
"1"
/>
The browser can’t display any image as expected, but it will still
make the request using the URL which will make a transaction without
notifying Alice.
The solution is to process any function that changes the database state in POST request, and avoid using
In addition, there should be a random token called a CSRF token associated with each POST request. When the user logins into his/her account, the application should generate a random token and store it in the session. Whenever any form is displayed to the user, the token should be present in the page as a hidden input field. Application logic must check for the token and ensure that it matches the token present in the session.
Take a look at the following example:
The solution is to process any function that changes the database state in POST request, and avoid using
$_REQUEST
. Use $_GET
to retrieve GET parameters, and use $_POST
to retrieve POST parameters.In addition, there should be a random token called a CSRF token associated with each POST request. When the user logins into his/her account, the application should generate a random token and store it in the session. Whenever any form is displayed to the user, the token should be present in the page as a hidden input field. Application logic must check for the token and ensure that it matches the token present in the session.
Preventing SQL Injection Attacks
To perform your database queries, you should be using PDO. With parameterized queries and prepared statements, you can prevent SQL injection.Take a look at the following example:
<?php
$sql
=
"SELECT * FROM users WHERE name=:name and age=:age"
;
$stmt
=
$db
->prepare(
$sql
);
$stmt
->execute(
array
(
":name"
=>
$name
,
":age"
=>
$age
));
In the above code we provide the named parameters :name
and :age
to prepare()
,
which informs the database engine to pre-compile the query and attach
the values to the named parameters later. When the call to execute()
is made, the query is executed with the actual values of the named
parameters. If you code this way, the attacker can’t inject malicious
SQL as the query is already compiled and your database will be secure.
Protecting the File System
As a developer you should always write your code in such a way that none
of your operations put your file system at risk. Consider the following
PHP that downloads a file according to a user supplied parameter:
<?php
if
(isset(
$_GET
[
'filename'
]) {
$filename
=
$_GET
[
'filename'
];
header(
'Content-Type: application/x-octet-stream'
);
header(
'Content-Transfer-Encoding: binary'
);
header(
'Content-Disposition: attachment; filename="'
.
$filename
.
'";'
);
echo
file_get_contents
(
$filename
);
}
The script is very dangerous since it can serve files from any
directory that is accessible to it, such as the session directory and
system directories. The solution is to ensure the script does not try to
access files from arbitrary directories.
A good way to guard your session data is to encrypt the information stored in the session. This does not solve the problem completely since the encrypted data is not completely safe, but at least the information is not readable. You should also consider keeping your session data stored somewhere else, such as a database. PHP provides a method called
As of PHP 5.4 you can pass an object of type
In production mode we need to turn off
You can use set_error_handler to define custom error handlers. However, it has limitations. The custom error handler bypasses the standard error handling mechanism of PHP. It cannot catch errors like
To handle errors elegantly you should perform exception handling through try/catch blocks. Exceptions are represented by the
Protecting Session Data
By default, session information is written to a temp directory. In the case of a shared hosting server, someone other than you can write a script and read session data easily. Therefore, you should not keep sensitive information like passwords or credit card numbers in a session.A good way to guard your session data is to encrypt the information stored in the session. This does not solve the problem completely since the encrypted data is not completely safe, but at least the information is not readable. You should also consider keeping your session data stored somewhere else, such as a database. PHP provides a method called
session_set_save_handler()
which can be used to persist data in session in your own way. As of PHP 5.4 you can pass an object of type
SessionHandlerInterface
to session_set_save_handler()
. Check out the PHP documentation to learn about implementing custom session persistence by implementing SessionHandlerInterface
.Proper Error Handling
It’s good to know about all the errors that occur while we’re developing an application, but when we make the application accessible to end users we should take care to hide the errors. If errors are shown to users, it may make our application vulnerable. So, the best approach is configuring your server differently for development and production environments.In production mode we need to turn off
display_errors
and display_start_up_errors
settings. error_reporting
and log_errors
should be on so that we can log errors while hiding those from end users.You can use set_error_handler to define custom error handlers. However, it has limitations. The custom error handler bypasses the standard error handling mechanism of PHP. It cannot catch errors like
E_CORE_ERROR
, E_STRICT
or E_COMPILER_ERROR
in the same file the error handler is defined in. Furthermore, it will
fail to handle errors that might occur within the handler itself.To handle errors elegantly you should perform exception handling through try/catch blocks. Exceptions are represented by the
Exception
class and its subclasses. If any error occurs inside the try block you
can throw an exception and process it in the catch block.
No comments:
Post a Comment