In this chapter, we will cover cross-site forgery. This topic is not exactly new, and believe it or not, we have already encountered this in the previous chapters. In this chapter, we will go deeper into cross-site forgery and learn the various techniques of defending against it.
Cross-site request forgery (CSRF) exploits the trust that a site has in a user's browser. It is also defined as an attack that forces an end user to execute unwanted actions on a web application in which the user is currently authenticated. We have seen at least two instances where CSRF has happened. Let's review these security issues now.
We will now take a look at a basic CSRF example:
chp4/python_tornado
. Run the following command:python xss_version.py
external.html
found in templates
, in another host, say http://localhost:8888
. You can do this by starting the server, which can be done by running python xss_version.py –port=8888
, and then visiting http://loaclhost:8888/todo_external
. You will see the following screenshot:http://localhost:8000/todo
and refreshing it, you will see the new to-do item added to the database, as shown in the following screenshot:http://localhost:8000/todo
, and you will see two subsequent alerts, as shown in the following screenshot:Take note that this can happen to the other backend written in other languages as well. Now go to your terminal, turn off the Python server backend, and change the directory to node/
. Start the node server by issuing this command:
node server.js
This time around, the server is running at http://localhost:8080
, so remember to change the $.post()
endpoint to http://localhost:8080
instead of http://localhost:8000
in external.html
, as shown in the following code:
function addTodo() {
var data = {
text: $('#todo_title').val(),
details:$('#todo_text').val()
}
// $.post('http://localhost:8000/api/todos', data, function(result) {
$.post('http://localhost:8080/api/todos', data, function(result) {
var item = todoTemplate(result.text, result.details);
$('#todos').prepend(item);
$("#todo-form").slideUp();
})
}
The line changed is found at addTodo()
; the highlighted code is the correct endpoint for this section.
external.html
, add a new to-do item containing JavaScript, as shown in the following screenshot:http://localhost:8080/api/
and refresh; you should see two alerts (or four alerts if you didn't delete the previous ones). The first alert is as follows:The second alert is as follows:
Now that we have seen what can happen to our app if we suffered a CSRF attack, let's think about how such attacks can happen.
Basically, such attacks can happen when our API endpoints (or URLs accepting the requests) are not protected at all. Attackers can exploit such vulnerabilities by simply observing which endpoints are used and attempt to exploit them by performing a basic HTTP POST operation to it.
If you are using modern frameworks or packages, the good news is that you can easily protect against such attacks by turning on or making use of CSRF protection. For example, for server.py
, you can turn on xsrf_cookie
by setting it to True
, as shown in the following code:
class Application(tornado.web.Application):
def __init__(self):
handlers = [
(r"/api/todos", Todos),
(r"/todo", TodoApp)
]
conn = pymongo.Connection("localhost")
self.db = conn["todos"]
settings = dict(
xsrf_cookies=True,
debug=True,
template_path=os.path.join(os.path.dirname(__file__), "templates"),
static_path=os.path.join(os.path.dirname(__file__), "static")
)
tornado.web.Application.__init__(self, handlers, **settings)
Note the highlighted line, where we set xsrf_cookies=True
.
For the version of the node server, you can refer to chp4/node/server_secure.js
, where we require csrf
. Have a look at the following code snippet:
var express = require('express'), var bodyParser = require('body-parser'), var app = express(); var session = require('cookie-session'), var csrf = require('csrf'), app.use(csrf()); app.use(bodyParser());
The highlighted lines are the new lines (compared to server.js
) to add in CSRF protection.
Now that both backends are equipped with CSRF protection, you can try to make the same post from external.html
. You will not be able to make any post from external.html
. For example, you can open Chrome's developer tool and go to Network. You will see the following:
On the terminal, you will see a 403
error from our Python server, which is shown in the following screenshot:
3.147.77.208