Secure GET and POST requests using PHP
Among the most traditional ways to send information between internet pages, electronic forms are widely used, as they help, a lot, transfer of data
This post is also available in the following languages: Portuguese.
In this article, we will cover two request methods: the GET and the POST methods, for sending and receiving data from an HTML form using PHP. Also, we will examine the most common problems involving information security, such as Cross-Site Scripting (XSS) and SQL Injection, and how to solve them with adequate sanitization.
Let's start with the theory: what are GET and POST requests, and how do they differ? – if you want to, you can skip to the next section, where we will start with the practice.
Understanding the GET and POST methods
The Hypertext Transfer Protocol (HTTP) was developed as a protocol to serve the transmission of documents, and works as an intermediary between internet browsers and web servers. You are used to reading it in the addresses of web pages – as well as its “brother”, the HTTPS, a more secure encrypted version (hence the “S” at the end, meaning “Secure”).
In other words, HTTP is a protocol that serves as a “bridge”: it collects a request from the internet browser; sends it to the server; waits for an answer; and, finally, it returns the new information to the browser.
Generally, these requests keep some metadata in their “header”, that contains messages used to perform certain behavior on the client or on the server. In addition, HTTP requests can assume different models.
The most used HTTP request types are GET and POST, but there are other types in their technical specification, such as PUT
, HEAD
, DELETE
, PATCH
and OPTIONS
. For the purposes of this article, we will focus only on the two most common.
The GET request
The GET request method is used when you want to obtain data from a specific source or resource. It should only be used to retrieval data, because its query string are sent and displayed at URL, for example: https://www.youtube.com/watch?v=fJ9rUzIMcZQ&t=3m5s
.
When we insert this URL into the browser, we are asking the YouTube server for a specific resource: to retrieve the data from the video v
identified as fJ9rUzIMcZQ
. As soon as the server “returns” the request, the HTTP protocol will tell the browser how to display the video, in this example, the official video for the song “Bohemian Rhapsody”, by the British band Queen.
Note that in our example, the second parameter of the GET request, the t
parameter, informs the start time that we expect in our response, in this case, from 3min and 5s. The parameters v
and t
are separated by the character &
, which indicates to the HTTP protocol where the “key-value” pairs of these parameters begin and end. So, the server knows exactly that you search for the video v=fJ9rUzIMcZQ
at the time t=3m5s
.
GET requests are generally limited in length — for most browsers, it is up to 8 KB, or 8192 bytes in URI — and, because they only serve to request data, they are not able to modify it. In addition, they can be stored in cache, in the browser's history and also in the bookmarks. That's why you should never use it to send sensitive data, such as Social Security Numbers and user passwords.
💡 Some developers, however, ignore it and expose personal and sensitive data of people on the internet. In Brazil, due to the General Personal Data Protection Law (LGPD), this practice may cause big inconveniences, such as serious penalties to the company or to the ones who operate and manage this data, when a leak happens. So, the best practice is to never send sensitive personal data via the GET method.
The POST request
The POST request method is used to send data to the server, to update or create a new resource.
Unlike the GET method, the POST method does not expose the information at the URL address. In this case, the data is transmitted in the HTTP request body, as follows:
POST /update/webform.php HTTP/1.1
Host: youtube.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 42
user=Stevie&playlist=British&v=fJ9rUzIMcZQ
In this example, we are informing the Host: youtube.com
server that we will make a POST
method request to the /update/webform.php
address, using the technical specifications of the HTTP/1.1
protocol. We are also indicating that there is a 42 character information (Content-Length: 42
), in the standard Content-Type
content format, whose value is application/x-www-form-urlencoded
. Finally, our information is on the bottom line, containing 3 parameters: user
, playlist
, and v
.
💡 The information traveling in the body of the HTTP request can be intercepted by bad agents. The best practice, then, is to make these transmissions using encryption, via the HTTPS protocol, so it makes harder to them read this information.
Let's assume the YouTube server recognized our request, and this address is valid. In our example, the informed video, which we received previously, will be added to the British
playlist of the user identified as Stevie
.
Note that this is a one-time request, which is unlikely to be repeated. As a rule, the POST method, unlike GET, is not stored in cache or in the client's browser history, nor can it be saved in bookmarks. POST requests have no restrictions on the size of messages, which allows us to send complete articles, such as this one, through an electronic HTML form, for example. Also, the POST method supports a wide variety of Content-Type
s, including binary documents, strings, and numbers.
💡 POST method is generally preferable over GET. However, there are situations in which we should include the requisition data in the address URL: for example, in search forms or by displaying documents and videos, because we want the client to be able to repeat it easily and to re-access the address through the browser's history.
Creating forms with HTML and PHP
Now that we understand how the GET and POST methods work in the theory, let's go to the practices: let's create an HTML form, and have it to send and to receive information using PHP.
💡 There are several ways to do this, like via JavaScript and AJAX, where the user don't have to refresh the page, because we are transmitting the information asynchronously. For the purposes of this article, we will focus only on HTML and PHP technologies.
Inserting the form on the page
The first step to create our web page is to inform the structure of the <form>
element that will contain the fields where user types the data, like this:
<!-- origin.html -->
<form method="GET" id="webform" name="webform" action="target.php">
</form>
In this fragment, we are using the GET method, defined in method="GET"
, to send the information that will be inserted into the form, whose name was defined in name="webform"
, to the target page (action="target.php"
).
Inserting the fields to the form
The next step is to insert the fields, or input
s to our form, where users can type the values. Let's update our source file like this:
<!-- origin.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Electronic form</title>
</head>
<body>
<form method="GET" id="webform" name="webform" action="target.php">
<label for="iduser">User ID:</label>
<input type="text" id="iduser" name="iduser"> <br />
<label for="idplaylist">Playlist ID:</label>
<input type="text" id="idplaylist" name="idplaylist"> <br />
<label for="v">Video ID:</label>
<input type="text" id="v" name="v" value="fJ9rUzIMcZQ"> <br />
<button type="submit">Send data</button>
</form>
</body>
</html>
We inserted 3 fields, defined by the HTML tag <input>
, and also 1 button that sends the form's data, using <button type="submit">
.
We also add labels to the text fields, using the <label>
tags. Notice that each values on the for
attributes, on each label
element corresponds to an id
attribute of one the input
fields, like this: <label for="idplaylist">
refers specifically to the field that contains the corresponding id="idplaylist"
attribute, and vice versa.
💡 It is possible to insert predefined values to the fields, adding the data corresponding to the
value
attribute in each HTML<input>
element.
Finally, the name
attribute in each <input>
field will be used to obtain the values inserted by the user in the corresponding field when we move to PHP.
The final result, displayed in the client's browser, should look like this:
Reading data with PHP
After completing our HTML form, we can move on to the next step. Let's define the elements of the target page using PHP.
The source code below, inserted in the file target.php
, will be executed by PHP as soon as the user submits the form data that we created earlier.
<!-- target.php -->
<?php
// Prints the values of each field on the page
echo(
"The user identified as " . $_GET["iduser"] . " added the video whose ID is " . $_GET["v"] . " to the playlist " . $_GET["idplaylist"] . "."
);
?>
Notice that we use the superglobal $_GET[]
variable to obtain the values inserted by the user, that were transmitted using the HTTP protocol. For each <input>
field that we previously created on the form, its corresponding name
attribute must be informed within the superglobal variable. For example: the <input>
field that shows the attribute name="iduser"
can be found in PHP by using $_GET["iduser]
.
PHP has some native superglobals variables, such as $_GET
, $_POST
, and $_REQUEST
. Remember that we use them according to the HTTP request method that we are using for data transmission, so it must correspond to what been defined in the method
attribute of our <form>
element.
💡 PHP's
$_REQUEST
superglobal variable can carry information from both$_GET
and$_POST
methods, in addition to any cookies transmitted in$_COOKIE
. However, its use is not always recommended: the best practice is that developers know the methods used for inputs and outputs traveling on their server, in order to avoid more generic commands.
Then, we separate the strings and the variables in PHP with the .
character, so each fragment of text is contained between the "
characters, at the beginning and at the end of the sentence. Finally, we print on the user's screen the entire expression within the parentheses with the echo()
function.
📝 Learn by doing
Did you notice that the URL address on target.php
page shows the values typed in the source page?
Test #1: Rewrite the source code of the form we coded, using another requisition method, so that the information stays safe from reading by eavesdroppers and unauthorized people. After you finish, you can check the final answer.
Increasing HTML form security
Our HTML form is finally done! However, we can increase the security of our page, protecting the reading of the information on PHP.
This is our last step. We will add an extra layer of security, although basic, to prevent PHP from executing commands at the moment it receives and displays the values reported by the client.
💡 The rule in programming is to never blindly trust the values inserted by the user. Unfortunately, many bad agents have exploited technical problems on websites in order to collect sensitive information, or to damage servers by executing unexpected commands. For those reasons, it is very important that you protect, beforehand, the transmitted requests and the server, after all, if the users' interests are legitimate, they will also benefit from the increased security of your application.
The technique that filters and transforms the values entered by the user into simpler strings is called sanitization. By default, PHP has a collection of native functions that helps us on this step, such as the following:
htmlspecialchars()
- Converts special characters, such as&“”<>
, to HTML entities;htmlentities()
- Similar to the previous one, but it converts a larger number of characters to HTML entities;strip_tags()
- Removes HTML and PHP tags from a string, such as hyperlinks and comments.
When we use adequate sanitization, as soon as the server receives an improper information — for example, <script>alert('Intrusive alert');</script>
— it will be transformed, “sanitized”, and should not display a warning message on the users' screen in this case.
💡 Notice that, in our example, we use a harmless, in theory, script — at most, uncomfortable for the user. However, it is important to reiterate: you must always protect and sanitize information. In other cases, a bad agent could transmit malicious scripts — this technique is known as Cross-Site Scripting, or XSS — or execute harmful commands to the database (usually called SQL Injection).
Let's edit the source code of our page, by adding one of these sanitizing functions. Our final code should look like this:
<!-- target.php -->
<?php
// Prints the values of each field on the page
echo(
"The user identified as " . htmlspecialchars($_GET["iduser"], ENT_QUOTES, "UTF-8") . " added the video whose ID is " . htmlspecialchars($_GET["v"], ENT_QUOTES, "UTF-8") . " to the playlist " . htmlspecialchars($_GET["idplaylist"], ENT_QUOTES, "UTF-8") . "."
);
?>
The final result, displayed in the browser, should look like the figure below:
📝 Learn by doing
Have you ever noticed that the majority of sites and search engines use the q
parameter to transmit the data inserted by the user in the query requests to the server?
Test #2: Create a search form, using HTML and PHP, that contains at least 1 text field and 1 button to send the data, so that the address URL on the target page displays the q
(or “query”) parameter. It should receive the values, sanitized, inserted by the user in the text field. After you finish, you can check the final answer.
Conclusion
So, we're done! We made our electronic form in HTML that is capable of transmitting data via HTTP request methods, in this case, GET or POST — and we also understand how they work —, and send them to the target page written in PHP. Then, it receives, handles the data, and displays the information on the user's screen. Also, we sanitized the values informed by the user in order to avoid serious problems of information security.
Next steps 🚶
Internet security it is never too much, so there is always something more to learn and apply. In order to build safer applications, be sure to follow the next article on this series, and read the Security topic in the PHP Manual.
If you have any questions or suggestions on how to build more secure applications using PHP, share it in the comments. 📣
References
[1] “HTTP Request Methods”, from w3schools: https://www.w3schools.com/tags/ref_httpmethods.asp.
[2] “HTTP”, from MDN Web Docs (Mozilla Developer Network): https://developer.mozilla.org/en-US/docs/Web/HTTP.
[3] “GET”, from MDN Web Docs (Mozilla Developer Network): https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET.
[4] “POST”, from MDN Web Docs (Mozilla Developer Network): https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST.
[5] “htmlspecialchars”, from PHP Manual: https://www.php.net/htmlspecialchars.
[6] “htmlentities”, from PHP Manual: https://www.php.net/htmlentities.
[7] “strip_tags”, from PHP Manual: https://www.php.net/strip_tags.
[8] “Superglobals”, from PHP Manual: https://www.php.net/manual/en/language.variables.superglobals.php.