description |
---|
Here resides some generic good security practices regarding web development |
Needless to say, most websites suffer from various types of bugs which may eventually lead to vulnerabilities. Why would this happen so often? There can be many factors involved including misconfiguration, shortage of engineers' security skills, etc. [1] We are here to combat this…
Here is a list of common attacks to cover ourselves from:
- XSS (Cross-Site Scripting)
- Use CSP to defend against some XSS attacks (inline scripts, remote scripts, unsafe JavaScript, form submissions, objects...)
- Understand your Framework Security. We have to be aware about how our framework prevents XSS and where it has gaps
- Ensure all variables go through validation and then escaped or sanitized correctly
- Use Output Encoding. Safely display data exactly as a user typed it in. Variables should not be interpreted as code instead of text. This applies to HTML, JS, CSS, URLs...
- Perform HTML Sanitization
- Use Safe Sinks
- Use Cookie attributes to change how JavaScript and browsers can interact with cookies
- The use of Web Application Firewalls (WAF) can block some known attack strings
- CSV Injection
- Ensure that no cells begins with these characters: "=", "+", "-", "@", tab "0x09", carriage return "0x0D"
- We need to ensure content will be read as text by the spreadsheet editor
- Take care of field separators and quotes
- Wrap each cell field in double quotes
- Prepend each cell field with a single quote
- Escape every double quote using an additional double quote
- SQL Injection
- If using an ORM, check about its SQLi defenses
- Use Prepared Statements (with Parametrized Queries)
- Use of properly constructed Stored Procedures
- Allow-list Input Validation
- Escape all User-Supplied Input
- Enforce Least privilege
- NoSQL injection
- Test for NoSQL injection vulnerabilities
- Avoid unsanitized user inputs in application code
- Some DBs has built-in features for secure query building... check them out
- Apply the rule of Least Privilege
- Know your language to avoid using vulnerable constructs
- XXE - XML eXternal Entity
- The safest way is to disable DTDs completely
- For detailed XXE prevention guidance, check the OWASP Cheatsheet
- CSRF - Cross-Site Request forgery
- Check if your framework has built-in CSRF protection and use it
- If not, add CSRF tokens to all state changing requests and validate them on the backend
- For stateful software use the synchronizer token pattern
- For stateless software use double submit cookies
- For API-driven sites that don't use
<form>
tags, use custom request headers - Consider using SameSite Cookie Attribute
- Consider implementing user interaction based protection for highly sensitive operations
- Verify the origin with standard headers
- Do NOT use GET requests for state changing operations
- If you need to do that, protect those resources against CSRF
- Check if your framework has built-in CSRF protection and use it
- Clickjacking (OWASP Clickjacking Defense Cheat Sheet)
- Prevent the browser from loading the page in an iframe by using X-Frame-Options or CSP headers (specially "frame-ancestors")
- Prevent sesion cookies from being included when the page is loaded in a frame using the SameSite cookie attribute
- Implement JavaScript code in the page to attempt to prevent it being loaded in a frame ("frame-buster" technique)
- SSRF - Server-Side Request forgery
- Check where the application can send request only to identified and trusted applications
- Use Input validation in all application layers
- Disable the support for the following of redirections to prevent the bypass of the input validation
- Apply the allow list approach
- Check where the application can send request to ANY external IP address or domain name
- Check where the application can send request only to identified and trusted applications
- Open Redirects
- Never allow open redirects as a default (if possible)
- Do not allow the URL as user input for destination (if possible)
- If user input can't be avoided
- Ensure it's valid
- Sanitize the input
- Ensure it's authorized
- Force redirects to go through a page notifying users they are going to another site and make them confirm
- If user input can't be avoided
- Follow an allow-list approach, rather than a block list
- Map the URL provided by the user to a short name (not enumerable) or hash to avoid tampering and reduce enumeration vulnerabilities
- File Uploads
- List allowed extensions, only allow safe and critical extensions for business functionallity
- Use input validation before validation the extensions
- Validate the file type, do NOT trust the Content-Type header (it can be spoofed)
- Change the filename to something generated by the application
- Set a filename length limit
- Restrict allowed characters in the filename
- Set a file size limit
- Only allow authorized users to upload files
- Store files on a different server or outside the webroot
- If you have to provide public access to these files use a handler to map filenames inside the application
- Run the file through an antivirus (such as VirusTotal) or in a sandbox, to validate it doesn't contain malicious data
- Ensure that used libraries for this purpose are securely configured and up to date
- Protect against CSRF attacks
- List allowed extensions, only allow safe and critical extensions for business functionallity
- CSP (Content Security Policies)
- Ensure to have a strong/strict CSP headers. Only allow what needed for your web to load
- Use hashes or nonces
- Upgrade insecure requests (or only serve via HTTPS)
- Enable a report directive to receive violations of prevented behaviours to specified locations
- Use tools to evaluate your CSP policy (such as CSP evaluator)
- Ensure to have a strong/strict CSP headers. Only allow what needed for your web to load
- Use HSTS (HTTP Strict Transport Security)
- See related problems nevertheless
- Cryptography
- See cryptography.md
- JWT (JSON Web Tokens)
- Do NOT include secrets in the payload
- Do NOT allow 'none' algorithm for signing (more info)
- Always verify the token (issuer, signature, retrieve actual public keys...)
- Avoid sensitive data exposure by not inserting a whole object into the JWT (break into parts, has to be lightweight)
- Use strong/recommended algorithms for signing
- Authentication
- UserIds
- Make sure they are case-insensitive and unique
- You can avoid username enumeration by mapping each username with an incremental ID internally and use a mapped hash (ex. using Hashids) to avoid enumeration
- If using email as user id, perform input validation
- Do NOT allow login with sensitive accounts (that can be used internally)
- Do NOT use same authentication solution for internal resources and for public access
- Implement proper password strength controls (see OWASP Password Storage Cheatsheet)
- Implement a proper "forgot password" mechanism (see OWASP Forgot Password Cheat Sheet)
- Store password securely (see OWASP Password Storage Cheatsheet)
- Always compare password hashes using safe functions
- Only allow authentication via HTTPs or other encrypted and strong transport
- Require re-authentication or 2FA/MFA for sensitive features
- Do NOT give hints in error messages to avoid enumeration attacks (be generic with error messages)
- Protect against automated attacks (see also OWASP Credential Stuffing Cheatsheet)
- Log and monitor your authentication mechanism
- Use authentication protocos that follow standards if possible (OAuth, OpenID, SAML, FIDO, Passkeys ...)
- Set
spellcheck="false"
in the HTML password field to avoid filtering the password (Spell-jacking) - Set
autocomplete="off"
if possible in the HTML password field - Let know the users about the benefits of using a password manager
- UserIds
- Cookies
- Always limit their access as possible
- Always set all Cookies with the "Secure" flag
- Avoid access to the cookie via JS by setting "HttpOnly"
- Set the expiration time ("Expires" & "Max-Age" directives) as soon as is necessary
- Set the "Domain" directive as restrictive as possible
- Set the "Path" directive as restrictive as possible
- Set the "SameSite" directive accordingly to your needs and the more restrictive possible ("Strict" always recommended)
- Consider enabling HTTP Public Key Pinning (HPKP)
- Set a Referrer Policy and consider never redirect a user to an external page with the referrer header (to be secretive)
- Create a restrictive "robots.txt" file to avoid robots crawl and disclose private information or portions of a website
- Try to load external data from CDNs or others by specifying the "integrity" and "crossorigin" attributes to enable "Subresource Integrity"
- Consider setting the header "X-Content-Type-Options" to avoid the client to guess the MIME type of the response (MIME type sniffing)
- Add a "security.txt" file in the root of your page to tell security researchers how to disclose vulnerabilities
Here is another check list of things to know about and protect (this does not mean they are less important!):
- Prototype Pollution
- HTTP Parameter Pollution
- Command Injection
- Deserialization attacks
- ORM Injection
- FTP Injection
- Web Cache Poisoning
- Relative Path Overwrite
- Remote Code Execution
- Header injection
- URLs problems
- Leaking
- Browser Exploitation
- ModSecurity (see OWASP ModSecurity Core Rule Set)
- SSL/TLS
- NFS
- Fingerprint
- Sub Domain Enumeration
- DNS Rebinding
- WAF (Web Application Firewalls)
- So you want to be a web security researcher? | PortSwigger Research
- OWASP Web Security Testing Guide | OWASP Foundation
- Mitigate cross-site scripting (XSS) with a strict Content Security Policy (CSP) (web.dev)
- Authentication - OWASP Cheat Sheet Series
- Web Security (mozilla.org)
- OWASP Cheat Sheet Series
[2]: Authentication - OWASP Cheat Sheet Series