Like many frameworks, Symfony provides built-in security. Symfony is pretty secure as a framework, but it would be a big mistake to entirely rely on that reputation to ensure the security of any application. Because every application is different, the security context is different. Therefore, developers still have a big role in ensuring everything is properly configured and tested.

Input filtering, authentication and session management… This series of articles will go through the different mechanisms that you, as a Symfony developer, can use to make sure the application you develop is safe and reliable.
And because built-in security does not necessarily mean “already done”, we will see what is really important and common pitfalls.

Symfony security padlock

Protecting your Symfony app against injections

If you don’t know what injections are, you will find useful information in this article: Understanding web vulnerabilities in 5 min – episode #1: injections!

Protecting your Symfony app against injections is quite simple.

As for any framework or language, the number one rule against injections is input validation:
You expect the user to provide a number for some of your form fields? Verify the data and ensure a number is actually provided.
Luckily, Symfony contains validation constraints and an easy way to implement custom constraints:

ALL inputs used by your application must be filtered. Form fields, url parameters, but also cookies or http headers, if some of them are handled by your app.
One learning from security audits we conducted on Symfony applications is that the vast majority of applications perform input validation. But some parameters are quite often missed out, somewhere. A good practice is to maintain a list of user inputs, and their corresponding security controls (for instance in the application’s specifications).

Regarding the database, using built-in mechanisms to interact with it is a good practice.

If you use Doctrine (which comes with the standard edition or symfony), then you are protected, at least when you use “classical” object queries.
When using DQL with custom queries, ensure you pass external values (coming from user inputs) as placeholders, with the setParameter method. This way, custom queries become “parameterized queries”, thus avoiding SQL injections.
DQL: http://symfony.com/doc/current/book/doctrine.html#querying-for-objects-with-dql

Doctrine is not the only solution, other ORMs like Propel also protects you from SQL injections, if you use them correctly.

If you perform OS commands or other sensitive queries, then you must properly think about escaping the input according to the context.

Handling authentication and sessions in a secure manner

Authentication is quite a big topic. We won’t go through all the details of what is possible with Symfony, the security cookbook is quite verbose on this subject.
To ensure your Symfony authentication is good, you can therefore go through the Authentication part of the cookbook: http://symfony.com/doc/current/cookbook/security/index.html

Some points you absolutely can’t miss:
– Ensuring your passwords are hashed in the database (with bcrypt, for instance).
– Ensure your cookies are “secure” (secure flag) and “httponly”. The secure flag does not make sense if your application is not protected with HTTPS, but if you give some importance to your users’ credentials (and you should), then HTTPS is a must-have.

Then, some additional points can be reinforced, in particular the protection against brute-force / dictionary attacks.
Enforcing a strong password policy is a first strategy, to avoid trivial password guessing: finding the right balance between convenience and security is the most difficult part.
If your application deals with very sensitive information, adding a Web Application Firewall to your infrastructure is an option to consider. Based on your budget and context, different solutions may apply. Some WAF are able to efficiently detect and block attackers, even if their IP address changes.

Cross Site Scripting protections in Symfony

Two rules against XSS:

  1. filter on input
  2. escape on output

Filtering must be done with constraints, like detailed earlier in the injection section.
Ensuring you get the right type of data from users will be a first protection. But for “complex” data, like free text fields (for a comment, description or any other text), almost anything can be provided.
If you need to allow some special characters, or even some html tags (caution!), you can use data transformers to implement specific and powerful data treatment.
Implementing data transformers: http://symfony.com/doc/current/cookbook/form/data_transformers.html

Escaping is also a must have, on the output.
Template engines like Twig do a good job on this, by allowing you to “escape” data (with the {{ user.username|escape }} syntax, for instance)
Reading more about this: http://symfony.com/doc/current/book/templating.html#output-escaping-in-twig

The Content Security Policy headers is also something you can implement in your project, to give clear instructions to web browsers.
This is usually done at the server level (nginx, httpd…) or directly on symfony using HttpFoundation.
Learning about the CSP: https://developer.mozilla.org/en-US/docs/Web/Security/CSP
And more generally about headers related to security: Secure your website with HTTP headers

Again, applying these best practices is great, but applying them everywhere on your app is a must.

Upcoming articles in this series will deal with other common security topics on symfony.
You can follow us on Twitter to keep posted.