Security

What is web security ?

  • Computer security

    Security is the protection of data and systems from unauthorized access, disclosure, modification, destruction or disruption.
    Computer security, also known as cybersecurity or IT security, is the protection of information systems from theft or damage to the hardware, the software, and to the information on them, as well as from disruption or misdirection of the services they provide.

  • Web Application Security

    Web application security is the protection of websites and online services from attacks and unauthorized access.
    Web application security draws on the principles of application security but applies them specifically to internet and web systems.

What is a Hacker ?

  • Hacker

    A hacker is a person who finds and exploits weaknesses in computer systems and/or networks to gain access.

  • White Hat Hacker

    A white hat hacker is a computer security specialist who breaks into protected systems and networks to test and asses their security.

  • Black Hat Hacker

    A black hat hacker is a computer security specialist who breaks into protected systems and networks to exploit and/or steal data.

  • Grey Hat Hacker

    A grey hat hacker is a computer security specialist who breaks into protected systems and networks to test and asses their security, but may also exploit and/or steal data.

Type of cyber attacks

  • Denial-of-Service (DoS) Attacks

    A denial-of-service (DoS) attack occurs when legitimate users are unable to access information systems, devices, or other network resources due to the actions of a malicious cyber threat actor.
    Denial-of-service attacks can be simple or complex. The attack attempts to overwhelm systems by consuming all available connections, bandwidth, or other system resources.
    A DoS attack can be targeted at any organization, regardless of size or industry.
    DoS attacks can be carried out in a number of ways. The most common include:

    • Consuming computational resources, such as bandwidth, disk space, or processor time.
    • Disrupting configuration information, such as routing information.
    • Disrupting state information, such as unsolicited resetting of TCP sessions.
    • Disrupting physical network components.

  • Spoofing

    Spoofing is the act of disguising a communication from an unknown source as being from a known, trusted source. Spoofing can apply to emails, phone calls, and websites, or can be more technical, such as a computer spoofing an IP address, Address Resolution Protocol (ARP), or Domain Name System (DNS) server.
    Spoofing is most prevalent in communication mechanisms that lack a high level of security.
    Spoofing can be used to gain access to a target's personal data, spread malware through infected links or attachments, bypass network access controls, or redistribute traffic to conduct a denial-of-service attack.

  • Phishing

    Phishing is the fraudulent attempt to obtain sensitive information or data, such as usernames, passwords and credit card details, by disguising oneself as a trustworthy entity in an electronic communication.

  • Pharming

    Pharming is a cyber attack intended to redirect a website's traffic to another, fake site.

  • Shoulder surfing

    Shoulder surfing is using direct observation techniques, such as looking over someone's shoulder, to get information.

  • Impersonation

    Impersonation is the act of pretending to be another person for the purpose of entertainment or fraud.

  • Watering hole attack

    A watering hole attack is a security exploit in which the attacker seeks to compromise a specific group of end users by infecting websites that members of the group are known to visit.

  • Identity-Based Attacks

    Identity-based attacks are a form of cyber attack in which the attacker uses stolen or forged credentials to gain access to a system.

  • Code Injection Attacks

    Code injection is the exploitation of a computer bug that is caused by processing invalid data. Code injection can be used by an attacker to introduce (or "inject") code into a computer program to change the course of execution.

General considerations

  • PHP is able to access files, execute commands and open network connections on the server. These properties make anything run on a web server insecure by default.
  • A completely secure system is a virtual impossibility, so an approach often used in the security profession is one of balancing risk and usability.
  • A phrase worth remembering: A system is only as good as the weakest link in a chain. If all transactions are heavily logged based on time, location, transaction type, etc. but the user is only verified based on a single cookie, the validity of tying the users to the transaction log is severely weakened.
  • When testing, keep in mind that you will not be able to test all possibilities for even the simplest of pages. The input you may expect will be completely unrelated to the input given by a disgruntled employee, a cracker with months of time on their hands.

Database Security

  • Designing Databases

    Applications should never connect to the database as its owner or a superuser, because these users can execute any query at will, for example, modifying the schema (e.g. dropping tables) or deleting its entire content. Instead, applications should connect as a user with the minimum privileges required to perform the necessary operations.
    For example, if an application only needs to read data from a table, it should connect as a user with SELECT privileges only. If an application needs to insert or update data, it should connect as a user with INSERT or UPDATE privileges only.
    If an application needs to perform multiple operations, it should connect as a user with the minimum privileges required to perform all of them.
    You may create different database users for every aspect of your application with very limited rights to database objects. The most required privileges should be granted only, and avoid that the same user can interact with the database in different use cases. This means that if intruders gain access to your database using your applications credentials, they can only effect as many changes as your application can.

  • Connecting to Database

    You may want to establish the connections over SSL to encrypt client/server communications for increased security, or you can use ssh to encrypt the network connection between clients and the database server. If either of these is used, then monitoring your traffic and gaining information about your database will be difficult for a would-be attacker.
    You should also consider using a firewall to restrict access to your database server. This will prevent unauthorized access to your database server from outside your network.

  • Encrypted Storage Model

    SSL/SSH protects data travelling from the client to the server: SSL/SSH does not protect persistent data stored in a database. SSL is an on-the-wire protocol.
    Once an attacker gains access to your database directly (bypassing the webserver), stored sensitive data may be exposed or misused, unless the information is protected by the database itself. Encrypting the data is a good way to mitigate this threat, but very few databases offer this type of data encryption.
    If you are using MySQL, you can use the MySQL Encryption functions to encrypt and decrypt data directly within the database.
    If you are using PostgreSQL, you can use the pgcrypto module to encrypt and decrypt data directly within the database.
    If you are using Oracle, you can use the Oracle Advanced Security Option to encrypt and decrypt data directly within the database.
    If you are using Microsoft SQL Server, you can use the SQL Server Encryption functions to encrypt and decrypt data directly within the database.
    The easiest way to work around this problem is to first create your own encryption package, and then use it from within your PHP scripts. PHP can assist you in this with several extensions, such as OpenSSL and Sodium, covering a wide variety of encryption algorithms. The script encrypts the data before inserting it into the database, and decrypts it when retrieving. See the references for further examples of how encryption works.

  • Hashing

    In the case of truly hidden data, if its raw representation is not needed (i.e. will not be displayed), hashing should be taken into consideration. The well-known example for hashing is storing the cryptographic hash of a password in a database, instead of the password itself.
    Hashing is a one-way operation, meaning that the original data cannot be retrieved from the hash. This is why it is a good way to store passwords, since the password itself is never stored, and the hash can be used to verify the password when the user logs in.
    Hashing is also used to verify the integrity of data, as a checksum. For example, if you download a file from a website, the website may also provide the hash of the file, so that you can verify that the file you downloaded is the same as the one on the website.
    The password functions provide a convenient way to hash sensitive data and work with these hashes.
    password_hash() is used to hash a given string using the strongest algorithm currently available and password_verify() checks whether the given password matches the hash stored in database.

PHP

<?php
// storing password hash
$query = sprintf("INSERT INTO users(name,pwd) VALUES('%s','%s');",
pg_escape_string($username),
password_hash($password, PASSWORD_DEFAULT));
$result = pg_query($connection, $query);
// querying if user submitted the right password
$query = sprintf("SELECT pwd FROM users WHERE name='%s';",
pg_escape_string($username));
$row = pg_fetch_assoc(pg_query($connection, $query));
if ($row && password_verify($password, $row['pwd'])) {
echo 'Welcome, ' . htmlspecialchars($username) . '!';
} else {
echo 'Authentication failed for ' . htmlspecialchars($username) . '.';
}
?>

Result

SQL Injection

  • SQL injection is a technique where an attacker exploits flaws in application code responsible for building dynamic SQL queries. The attacker can gain access to privileged sections of the application, retrieve all information from the database, tamper with existing data, or even execute dangerous system-level commands on the database host. The vulnerability occurs when developers concatenate or interpolate arbitrary input in their SQL statements.
    The most common SQL injection attack is the insertion of a SQL query via the input data from the client to the application. The attacker can insert SQL code into the application input, which is then passed to the database. The database executes the SQL code, which allows the attacker to steal data, modify data, or even execute dangerous system-level commands on the database host.

PHP

<?php
$username = $_GET['username'];

// beware, no input validation!

$password = $_GET['password'];

// beware, no input validation!

$query = "SELECT id, name FROM users WHERE username='$username' AND password='$password'";
?>

Result

In the following example, user input is directly interpolated into the SQL query allowing the attacker to gain a superuser account in the database.
Normal users click on the 'next', 'prev' links where the $offset is encoded into the URL. The script expects that the incoming $offset is a number. However, what if someone tries to break in by appending the following to the URL.

&offset=1; INSERT INTO users (username, password) VALUES ('hacker', 'hacker'); --

If it happened, the script would present a superuser access to the attacker. Note that 1; is to supply a valid offset to the original query and to terminate it. The rest of the query is to insert a new user into the database. The -- is to comment out the rest of the original query.
The following example shows how to fix the problem by using prepared statements.
Prepared statements are a two-step mechanism. First, the application sends a SQL statement template to the database. The database parses, compiles, and performs query optimization on the SQL statement template, and stores the result without executing it.
Second, the application binds user input to parameters in the prepared statement, and the database executes the statement. The application may execute the statement as many times as it wants with different values.
A feasible way to gain passwords is to circumvent your search result pages. The only thing the attacker needs to do is to see if there are any submitted variables used in SQL statements which are not handled properly. These filters can be set commonly in a preceding form to customize WHERE, ORDER BY, LIMIT and OFFSET clauses in SELECT statements. If your database supports the UNION construct, the attacker may try to append an entire query to the original one to list passwords from an arbitrary table. It is strongly recommended to store only secure hashes of passwords instead of the passwords themselves.
Using parameterized queries isn't enough to entirely avoid SQL injection, but it is the easiest and safest way to provide input to SQL statements. All dynamic data literals in WHERE, SET, and VALUES clauses must be replaced with placeholders. The actual data will be bound during the execution and sent separately from the SQL command.
SQL injection attacks are mainly based on exploiting the code not being written with security in mind. Never trust any input, especially from the client side, even though it comes from a select box, a hidden input field, or a cookie.
A defense-in-depth strategy involves several good coding practices:
  • Never connect to the database as a superuser or as the database owner. Use always customized users with minimal privileges.
  • Check if the given input has the expected data type (Regular Expressions).
  • If the application expects numerical input, consider verifying data with ctype_digit(), silently change its type using settype(), or use its numeric representation by sprintf().
  • If the database layer doesn't support binding variables then quote each non-numeric user-supplied value that is passed to the database with the database-specific string escape function (e.g. mysql_real_escape_string(), sqlite_escape_string(), etc.). Be aware that addslashes() is not sufficient to protect your data against modern SQL injection attacks.
  • Do not print out any database-specific information, especially about the schema. This information can be used to exploit the database.

Cross-Site Scripting (XSS)

XSS PHP Injection is a type of attack in which malicious scripts are injected into otherwise benign and trusted websites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application uses input from a user within the output it generates without validating or encoding it.
An attacker can use XSS to send a malicious script to an unsuspecting user. The end user's browser has no way to know that the script should not be trusted, and will execute the script. Because it thinks the script came from a trusted source, the malicious script can access any cookies, session tokens, or other sensitive information retained by the browser and used with that site. These scripts can even rewrite the content of the HTML page.
XSS attacks can generally be categorized into three categories:
  • Reflected XSS Attacks
  • Stored XSS Attacks
  • DOM-based XSS Attacks

Reflected XSS Attacks

Reflected XSS attacks are those where the injected script is reflected off the web server, such as in an error message, search result, or any other response that includes some or all of the input sent to the server as part of the request. Reflected attacks are delivered to victims via another route, such as in an e-mail message, or on some other website. When a user is tricked into clicking on a malicious link, submitting a specially crafted form, or even just browsing to a malicious site, the injected code travels to the vulnerable website, which reflects the attack back to the user's browser. The browser then executes the code because it came from a "trusted" server. Reflected XSS attacks are also sometimes referred to as non-persistent attacks or Type-II XSS.
Reflected XSS Example:

<?php
$search = $_GET['search'];
echo "You searched for: $search";
?>

If the user enters the following URL into the browser:

http://example.com/search.php?search=<script>alert('XSS')</script>
The following output will be generated:

You searched for: <script>alert('XSS')</script>
The browser will execute the script because it came from a "trusted" server.

Stored XSS Attacks

Stored XSS attacks are those where the injected script is permanently stored on the target servers, such as in a database, in a message forum, visitor log, comment field, etc. The victim then retrieves the malicious script from the server when it requests the stored information. Stored XSS is also sometimes referred to as persistent XSS or Type-I XSS.
Stored XSS Example:

<?php
$comment = $_GET['comment'];
$sql = "INSERT INTO comments (comment) VALUES ('$comment')";
$result = mysql_query($sql);
?>

If the user enters the following URL into the browser:

http://example.com/comment.php?comment=<script>alert('XSS')</script>
The following comment will be stored in the database:

<script>alert('XSS')</script>
When another user visits the comments page, the following output will be generated:

<script>alert('XSS')</script>
The browser will execute the script because it came from a "trusted" server.

DOM-based XSS Attacks

DOM-based XSS attacks are those where the payload is executed as a result of modifying the DOM “environment” in the victim's browser used by the original client side script, so that the client side code runs in an “unexpected” manner. That is, the page itself (the HTTP response that is) does not change, but the client side code contained in the page executes differently due to the malicious modifications that have occurred in the DOM environment. While DOM-based XSS is conceptually simple, detecting whether a particular application is vulnerable to DOM-based XSS is much more difficult.
DOM-based XSS Example:

<?php
$search = $_GET['search'];
echo "You searched for: $search";
?>

If the user enters the following URL into the browser:

http://example.com/search.php?search=<script>alert('XSS')</script>
The following output will be generated:

You searched for: <script>alert('XSS')</script>
The browser will execute the script because it came from a "trusted" server.

Preventing XSS

The key to preventing XSS attacks is to ensure that user input is properly sanitized and validated before being used in your application.
The following example shows how to fix the problem by using htmlspecialchars() to sanitize the user input.

<?php
$search = htmlspecialchars($_GET['search']);
echo "You searched for: $search";
?>

If the user enters the following URL into the browser:

http://example.com/search.php?search=<script>alert('XSS')</script>
The following output will be generated:

You searched for: <script>alert('XSS')</script>
The browser will not execute the script because it is not a valid HTML tag.

Securing Session INI Settings

  • session.cookie_lifetime=0

    0 possesses a particular meaning. It informs browsers not to store the cookie to permanent storage. Therefore, when the browser is terminated, the session ID cookie is deleted immediately. If developers set this other than 0, it may allow other users to use the session ID. Most applications should use "0" for this.

  • session.use_only_cookies=On

    Although HTTP cookies suffer some problems, cookies remain the preferred way to manage session IDs. Only use cookies for session ID management when it is possible. Most applications should use a cookie for the session ID.
    If session.use_only_cookies=Off, the session module will use the session ID values set by GET or POST provided the session ID cookie is uninitialized. This is a potential security hazard because session ID values are exposed in the URL.

  • session.use_strict_mode=On

    Although, enabling session.use_strict_mode is mandatory for secure sessions. It is disabled by default.
    This prevents the session module to use an uninitialized session ID. Put differently, the session module only accepts valid session IDs generated by the session module. It rejects any session ID supplied by users.
    If session.use_strict_mode=Off, the session module will accept uninitialized session ID sent by users.
    For example, a hacker can use a session ID of another user to hijack the session. This is done by manipulating the session ID in the URL.

  • session.cookie_httponly=On

    Refuses access to the session cookie from JavaScript. This setting prevents cookies snatched by a JavaScript injection.
    If session.cookie_httponly=Off, the session cookie is accessible from JavaScript. This is a potential security hazard.
    For example, a hacker can use a JavaScript injection to steal the session cookie. This is done by injecting a JavaScript code that sends the session cookie to the hacker's server.

  • session.cookie_secure=On

    Allow access to the session ID cookie only when the protocol is HTTPS. If a website is only accessible via HTTPS, it should enable this setting.
    If session.cookie_secure=Off, the session ID cookie is accessible via HTTP. This is a potential security hazard.
    HTTPS is a secure protocol that encrypts data between the client and the server. It prevents hackers from eavesdropping on the communication between the client and the server.

  • session.cookie_samesite="Lax" or session.cookie_samesite="Strict"

    As of PHP 7.3 the "SameSite" attribute can be set for the session ID cookie. This attribute is a way to mitigate CSRF (Cross Site Request Forgery) attacks.
    If session.cookie_samesite="None", the session ID cookie is accessible from any domain. This is a potential security hazard.
    The difference between Lax and Strict is the accessibility of the cookie in requests originating from another registrable domain employing the HTTP GET method. Cookies using Lax will be accessible in a GET request originated from another registrable domain, whereas cookies using Strict will not.
    For example, if the current domain is example.com, the session ID cookie is accessible in a GET request originated from another domain such as example.net if session.cookie_samesite="Lax".

  • session.gc_maxlifetime=[choose smallest possible]

    session.gc_maxlifetime is a setting for deleting obsolete session ID. Reliance on this setting is not recommended. Developers should manage the lifetime of sessions with a timestamp by themselves.
    If session.gc_maxlifetime is set to a large value, it may allow other users to use the session ID.
    For example, if session.gc_maxlifetime=86400, the session ID is valid for 24 hours. If a hacker can obtain the session ID, he can use it to hijack the session for 24 hours.

  • session.use_trans_sid=Off

    Use of a transparent session ID management is not prohibited. Developers may employ it when it is required. However, disabling transparent session ID management improves the general session ID security by eliminating the possibility of a session ID injection and/or leak.
    Session ID may leak from bookmarked URLs, e-mailed URLs, saved HTML source, etc.

  • session.trans_sid_tags=[limited tags]

    (PHP 7.1.0 >=) Developers should not rewrite unneeded HTML tags. Default value should be sufficient for most usages. Older PHP versions use url_rewriter.tags instead.

  • session.trans_sid_hosts=[limited hosts]

    (PHP 7.1.0 >=) This INI defines whitelist hosts that allows trans sid rewrite. Never add untrusted hosts. Session module only allows $_SERVER['HTTP_HOST'] when this setting is empty. Older PHP versions use url_rewriter.hosts instead.

  • session.referer_check=[originating URL]

    When session.use_trans_sid is enabled. It reduces the risk of session ID injection. If a website is http://example.com/, set http://example.com/ to it. Note that with HTTPS browsers will not send the referrer header. Browsers may not send the referrer header by configuration. Therefore, this setting is not a reliable security measure. Use of this setting is recommended.

  • session.cache_limiter=nocache

    Ensure HTTP content are uncached for authenticated sessions. Allow caching only when the content is not private. Otherwise, content may be exposed. "private" may be employed if HTTP content does not include security sensitive data. Note that "private" may transmit private data cached by shared clients. "public" must only be used when HTTP content does not contain any private data at all.
    "nocache" is the most secure setting. It instructs browsers not to cache HTTP content at all. This setting is recommended.

  • session.sid_length="48"

    (PHP 7.1.0 >=) Longer session IDs results in stronger session IDs. Developers should consider a session ID length of 32 characters or more. At least 26 characters are required when session.sid_bits_per_character="5".

  • session.sid_bits_per_character="6"

    (PHP 7.1.0 >=) The more bits there are in a session ID character, the stronger the session ID generated by the session module is for an identical session ID length.

  • session.hash_function="sha256"

    (PHP 7.1.0 ) A stronger hash function will generate a stronger session ID. Although hash collision is unlikely even with the MD5 hashing algorithm, developers should use SHA-2 or a stronger hashing algorithm like sha384 and sha512. Developers must ensure they feed a long enough entropy for the hashing function used.

  • session.save_path=[non world-readable directory]

    (PHP 7.1.0 ) Developers should not use a world-readable directory for storing session data. This is a potential security hazard.
    If session.save_path is set to a world-readable directory, it may allow other users to use the session ID.
    For example, if session.save_path="/tmp", the session ID is stored in a world-readable directory. If a hacker can obtain the session ID, he can use it to hijack the session.

Filesystem Security

  • Since PHP was designed to allow user level access to the filesystem, it's entirely possible to write a PHP script that will allow you to read system files such as /etc/passwd, modify your ethernet connections, send massive printer jobs out, etc. This has some obvious implications, in that you need to ensure that the files that you read from and write to are the appropriate ones.

PHP

<?php
// remove a file from the user's home directory
$username = $_POST['user_submitted_name'];
$userfile = $_POST['user_submitted_filname'];
$homedir = "/home/$username";

unlink("$homedir/$userfile");

echo "The file has been deleted!";
?>

Result

Since the username and the filename are postable from a user form, they can submit a username and a filename belonging to someone else, and delete it even if they're not supposed to be allowed to do so. In this case, you'd want to use some other form of authentication. Consider what could happen if the variables submitted were "../etc/" and "passwd". The code would then effectively read:

PHP

<?php
// removes a file from anywhere on the hard drive that
// the PHP user has access to. If PHP has root access:
$username = $_POST['user_submitted_name']; // "../etc"
$userfile = $_POST['user_submitted_filename']; // "passwd"
$homedir = "/home/$username"; // "/home/../etc"

unlink("$homedir/$userfile"); // "/home/../etc/passwd"

echo "The file has been deleted!";
?>

Result

There are two important measures you should take to prevent these issues.
  • Only allow limited permissions to the PHP web user binary.
  • Check all variables which are submitted.

PHP

<?php
// removes a file from the hard drive that
// the PHP user has access to.
$username = $_SERVER['REMOTE_USER']; // using an authentication mechanism
$userfile = basename($_POST['user_submitted_filename']);
$homedir = "/home/$username";
$filepath = "$homedir/$userfile";
if (file_exists($filepath) && unlink($filepath)) {
$logstring = "Deleted $filepath\n";
} else {
$logstring = "Failed to delete $filepath\n";
}
$fp = fopen("/home/logging/filedelete.log", "a");
fwrite($fp, $logstring);
fclose($fp);
echo htmlentities($logstring, ENT_QUOTES);
?>

Result