Resource
- https://martinfowler.com/articles/web-security-basics.html
Abstract
Input
Data that falls outside of an expected set of values can cause our application to yield unexpected results, for example violating business logic, triggering faults, and even allowing an attacker to take control of resources or the application itself.
Input that is evaluated on the server as executable code, such as a database query, or executed on the client as HTML JavaScript is particularly dangerous. Validating input is an important first line of defense to protect against this risk.
Another way of thinking of input validation is that it is enforcement of the contract your form handling code has with its consumer. Anything violating that contract is invalid and therefore rejected. The more restrictive your contract, the more aggressively it is enforced, the less likely your application is to fall prey to security vulnerabilities that arise from unanticipated conditions.
You are going to have to make a choice about exactly what to do when input fails validation. The most restrictive and, arguably most desirable is to reject it entirely, without feedback, and make sure the incident is noted through logging or monitoring.
- White list when you can, e.g. number input limited to a small range.
- Black list when you can't whitelist,
- Keep your contract as restrictive as possible
- Make sure you alert about the possible attack
- Avoid reflecting input back to a user
- Reject the web content before it gets deeper into application logic to minimize ways to mishandle untrusted data or, even better, use your web framework to whitelist input
Output
In addition to limiting data coming into an application, web application developers need to pay close attention to the data as it comes out. A modern web application usually has basic HTML markup for document structure, CSS for document style, JavaScript for application logic, and user-generated content which can be any of these things. It's all text. And it's often all rendered to the same document.
HTML is a very, very permissive format. Browsers try their best to render the content, even if it is malformed. That may seem beneficial to the developer since a bad bracket doesn't just explode in an error, however, the rendering of badly formed markup is a major source of vulnerabilities. Attackers have the luxury of injecting content into your pages to break through execution contexts, without even having to worry about whether the page is valid.
developers should be rejecting input that falls outside the bounds of the contract, but what do we do when we need to accept input containing characters that has the potential to change our code, like a single quote ("'
") or open bracket ("<
")? This is where output encoding comes in.
Output encoding is converting outgoing data to a final output format. The complication with output encoding is that you need a different codec depending on how the outgoing data is going to be consumed. Without appropriate output encoding, an application could provide its client with misformatted data making it unusable, or even worse, dangerous. An attacker who stumbles across insufficient or inappropriate encoding knows that they have a potential vulnerability that might allow them to fundamentally alter the structure of the output from the intent of the developer.
There are so many tools and frameworks these days, and so many encoding contexts (e.g. HTML, XML, JavaScript, PDF, CSS, SQL, etc.), that creating a comprehensive list is infeasible. Just because a framework renders HTML safely, doesn’t mean it’s going to render JavaScript or PDFs safely. You need to be aware of the encoding a particular context the encoding tool is written for.
- Output encode all application data on output with an appropriate codec
- Use your framework's output encoding capability, if available
- Avoid nested rendering contexts as much as possible
- Store your data in raw form and encode at rendering time
- Avoid unsafe framework and JavaScript calls that avoid encoding
Bind Parameters
If SQL is built through concatenation, interpolation, or formatting methods, none of the resulting string should be created from user input.
- Avoid building SQL (or NoSQL equivalent) from user input
- Bind all parameterized data, both queries and stored procedures
- Use the native driver binding function rather than trying to handle the encoding yourself
- Don't think stored procedures or ORM tools will save you. You need to use binding functions for those, too
- NoSQL doesn't make you injection-proof
Data In-Transit
- Use HTTPS for everything!
- Use HSTS to enforce it
- You will need a certificate from a trusted certificate authority if you plan to trust normal web browsers
- Protect your private key
- Use a configuration tool to help adopt a secure HTTPS configuration
- Set the "secure" flag in cookies
- Be mindful not to leak sensitive data in URLs
- Verify your server configuration after enabling HTTPS and every few months thereafter
Hash and Salt Password
- Hash and salt all passwords
- Use an algorithm that is recognized as secure and sufficiently slow
- Ideally, make your password storage mechanism configurable so it can evolve
- Avoid storing passwords for external systems and services
- Be careful not to set password size limits that are too small, or character set limits that are too narrow
Authenticate User Safely
- Use existing authentication frameworks whenever possible instead of creating one yourself
- Support authentication methods that make sense for your needs
- Limit the ability of an attacker to take control of an account
- You can take steps to prevent attacks to identify or compromise accounts
- Never use default or hard-coded credentials
Protect User Session
- Use existing session management frameworks instead of creating your own
- Keep session identifiers secret, do not use them in URLs or logs
- Protect session cookies using attributes to restrict their scope
- Domain
- Path
- HTTPOnly : The HttpOnly flag instructs the browser that the cookie should not be accessible through JavaScript or other client side scripts, which helps prevent it being stolen by malicious code.
- Secure : only transfer cookie under HTTPS
-
Set-Cookie: sessionId=[top secret value]; path=/secret/; secure; HttpOnly; domain=payments.martinfowler.com
- Create a new session when one doesn't exist or whenever a user changes their privilege level
- Never create sessions with ids you haven't created yourself
- Make sure users have a way to log out and to terminate their existing sessions