Skip to main content

Web Security Basics - How to Not Get Hacked

By · · 9 min read

Security Basics - Because Getting Hacked Sucks

Introduction: The Day My App Got Hacked

I was launching my first real project. Pretty proud of it. Then one day I checked the database and noticed something weird: random user records were showing up that didn't exist. Someone had found an SQL injection vulnerability in my login code.

My heart sank. I immediately pulled it down, fixed it, reviewed everything else for holes. That scared me straight.

I realized: security isn't some enterprise thing. Any app can get attacked. My little homework project, your first web app—all targets. You don't need to be Facebook to be worth attacking.

So I learned how attacks actually work, not as theory but as "oh, I see how someone could break my code." Then I learned how to stop them.

This guide covers practical security. Real attacks, real defenses, real code examples.


1. Security Fundamentals - CIA Triad

The Three Pillars of Information Security

Confidentiality - Only authorized users access information

  • Encryption protects data
  • Access controls limit visibility
  • Example: Passwords never transmitted in plaintext

Integrity - Data unchanged and authentic

  • Hash verification detects tampering
  • Digital signatures prove source
  • Checksums catch corruption
  • Example: Database checksums detect unauthorized changes

Availability - Service accessible when needed

  • Redundancy prevents single points of failure
  • Load balancing distributes load
  • Backup systems enable recovery
  • Example: CDN ensures website available worldwide

Attack Surface Analysis

Every application has potential entry points:

Web Application Attack Surface:
┌──────────────┐
│   Browser    │ ← XSS attacks inject malicious scripts
└──────┬───────┘
       │ HTTP/HTTPS
┌──────┴───────┐
│  Web Server  │ ← DDoS, vulnerability exploitation
└──────┬───────┘
       │ API
┌──────┴───────┐
│  Application │ ← SQL injection, auth bypass, logic flaws
└──────┬───────┘
       │ Database
┌──────┴───────┐
│  Database    │ ← Data exfiltration, ransomware
└──────────────┘

2. Cryptography - The Foundation

Symmetric Encryption (Same Key for Encrypt/Decrypt)

Key: "SecretKey123"

Plaintext: "Transfer $1,000"
  ↓ [Encrypt with Key]
Ciphertext: "7X$k@Lq!9mZ^"
  ↓ [Decrypt with Key]
Plaintext: "Transfer $1,000"

Algorithms: AES-256 (government standard), DES (deprecated)
Use for: Encrypting stored data, secure communication
Strength: Fast, symmetric (shared secret required)
Weakness: Key distribution problem

Asymmetric Encryption (Public/Private Key)

Alice's Key Pair:
  Public Key: Share with everyone
  Private Key: Keep secret

Process:
1. Bob encrypts with Alice's PUBLIC key
2. Alice decrypts with her PRIVATE key

Only Alice can decrypt (she's only one with private key)
Encryption ≠ Authentication

Algorithms: RSA, ECC
Use for: SSL/TLS certificates, digital signatures
Strength: No shared secret needed, can be public
Weakness: Slower than symmetric

Hashing (One-Way Function)

Input: "password123"
  ↓ [Hash Function - SHA-256]
Output: "ef92b778bafe771e89245d171baf..."

Properties:
- Deterministic: Same input → same hash
- Fast computation
- Avalanche effect: Small input change → completely different hash
- One-way: Cannot reverse (compute input from hash)
- Collision-resistant: Nearly impossible to find two inputs with same hash

Use for: Password storage, data integrity verification
Never: Plain SHA-256 for passwords (too fast for brute force)
Better: bcrypt, Argon2 (slow hashing for passwords)

SSL/TLS Certificate and HTTPS

HTTPS Handshake Process:

1. Client connects
2. Server sends certificate (contains public key)
3. Client verifies certificate (signed by CA)
4. Client generates random symmetric key
5. Client encrypts symmetric key with server's public key
6. Server decrypts using its private key
7. Both have symmetric key - encrypted communication begins

Result: Confidentiality + Integrity + Authentication

Certificate Components:
- Subject (domain)
- Issuer (Certificate Authority)
- Public key
- Validity dates
- Signature (proves issuer verified domain)

3. Common Web Vulnerabilities - OWASP Top 10

1. SQL Injection - Injecting Malicious SQL

// VULNERABLE CODE
const username = req.body.username;
const password = req.body.password;

const query = "SELECT * FROM users WHERE username='" + username + 
              "' AND password='" + password + "'";
db.execute(query);

// Attack:
// username: admin' --
// password: anything
// Resulting Query: SELECT * FROM users WHERE username='admin' --' AND password='anything'
// Comment "--" removes password check → bypasses authentication!

// SECURE: Use parameterized queries
const query = "SELECT * FROM users WHERE username=? AND password=?";
db.execute(query, [username, password]);
// Treats username/password as data, not SQL code

2. Cross-Site Scripting (XSS) - Injecting Malicious Scripts

<!-- VULNERABLE: Direct output without escaping -->
<p>Search results for: <%= searchTerm %></p>

<!-- Attack: searchTerm = "<script>alert('hacked')</script>" -->
<!-- Results in malicious script execution -->

<!-- SECURE: Escape HTML -->
<p>Search results for: <%= escapeHtml(searchTerm) %></p>

<!-- Template frameworks auto-escape -->
<!-- Vue: {{ searchTerm }} - auto-escaped -->
<!-- React: {searchTerm} - auto-escaped (JSX) -->

3. Cross-Site Request Forgery (CSRF)

// Attack scenario:
// 1. User logged into bank.com
// 2. User visits attacker.com (without logging out)
// 3. attacker.com has:
<img src="https://bank.com/transfer?to=attacker&amount=1000">
// 4. Browser sends request with user's bank session cookie!
// 5. Transfer happens without user knowledge

// DEFENSE: CSRF Tokens
// Form includes unique token
<form method="POST" action="/transfer">
  <input type="hidden" name="csrf_token" value="unique_random_token">
  <input type="text" name="amount">
  <button>Transfer</button>
</form>

// Server verifies token matches user's session
// Attacker cannot get token → attack fails

4. Broken Authentication

// VULNERABLE: Weak password requirements
if (password.length < 3) {
    // Accept "abc" as password!
}

// VULNERABLE: No rate limiting
for (let i = 0; i < 1000000; i++) {
    tryLogin('admin', 'password' + i);  // Brute force
}

// SECURE: 
// - Min 12 characters, mix of char types
// - Rate limiting (max 5 attempts, 15 min lockout)
// - Password history (prevent reuse)
// - MFA (multi-factor authentication)
// - Secure password reset (email verification)

// MFA Implementation
const secret = speakeasy.generateSecret({ name: 'AppName' });
user.mfaSecret = secret.base32;

// User scans QR code with authenticator app
// On login: verify 6-digit code from authenticator
const verified = speakeasy.totp.verify({
    secret: user.mfaSecret,
    encoding: 'base32',
    token: userToken
});

5. Sensitive Data Exposure

// VULNERABLE: Logging sensitive data
console.log('User logged in:', { username, password, token });
// Logs appear in production logs, accessible to many

// VULNERABLE: Storing passwords plaintext
db.insert('users', {
    username: 'raj',
    password: 'MyPassword123'  // NEVER!
});

// SECURE: Hash passwords with strong algorithm
const bcrypt = require('bcrypt');
const hashedPassword = await bcrypt.hash(password, 10);
db.insert('users', {
    username: 'raj',
    password: hashedPassword
});

// On login: verify
const match = await bcrypt.compare(inputPassword, storedHash);

// SECURE: Don't log sensitive data
console.log('User logged in:', { username });

6. Broken Access Control

// VULNERABLE: No authorization check
app.get('/user/:id', (req, res) => {
    const user = db.getUser(req.params.id);
    res.json(user);  // Anyone can request any user
});

// SECURE: Verify authorization
app.get('/user/:id', (req, res) => {
    if (req.params.id !== req.user.id && !req.user.isAdmin) {
        return res.status(403).json({ error: 'Forbidden' });
    }
    const user = db.getUser(req.params.id);
    res.json(user);
});

// VULNERABLE: Direct Object Reference
// URL: /orders/12345
// User can change to /orders/12346 → see others' orders

// SECURE: Verify user owns resource
app.get('/orders/:id', (req, res) => {
    const order = db.getOrder(req.params.id);
    if (order.userId !== req.user.id) {
        return res.status(403).json({ error: 'Forbidden' });
    }
    res.json(order);
});

7. Insecure Configuration

// VULNERABLE: Debug mode in production
app.set('debug', true);
// Exposes stack traces, sensitive information

// VULNERABLE: Default credentials
const defaultAdmin = { username: 'admin', password: 'admin' };
// Anyone can access with default password

// VULNERABLE: Outdated dependencies
// package.json still using 5-year-old libraries with known vulnerabilities

// SECURE:
// - Turn off debug mode in production
// - Change default credentials
// - Run security audits: npm audit
// - Use environment variables for secrets
const dbPassword = process.env.DB_PASSWORD;
// - Least privilege principle (users only need minimum permissions)
// - Remove unnecessary services/features
// - Keep systems updated

8. Unvalidated Redirects and Forwards

// VULNERABLE: Trust user input for redirect
app.get('/redirect', (req, res) => {
    res.redirect(req.query.url);  // User provides URL
});

// Attack: /redirect?url=https://malicious.com
// User thinks clicking legitimate link, redirected to phishing site

// SECURE: Whitelist allowed URLs
const allowedUrls = ['/', '/home', '/profile'];
const redirectUrl = req.query.url;

if (allowedUrls.includes(redirectUrl)) {
    res.redirect(redirectUrl);
} else {
    res.redirect('/');
}

9. XML External Entities (XXE)

<!-- VULNERABLE: XML parsing without XXE protection -->
<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<data>&xxe;</data>

<!-- Attack: Reads local files, causes DDoS, port scanning -->

<!-- SECURE: Disable external entities -->
// Node.js example
const parser = new DOMParser();
parser.external = false;  // Disable external entities

10. Using Components with Known Vulnerabilities

// VULNERABLE: Using outdated npm package
// package.json
{
  "dependencies": {
    "lodash": "2.4.1"  // Very old version with vulnerabilities
  }
}

// SECURE: Keep dependencies updated
npm audit  // Identifies vulnerable packages
npm audit fix  // Auto-fixes fixable vulnerabilities

// package.json
{
  "dependencies": {
    "lodash": "^4.17.21"  // Latest stable version
  }
}

// CI/CD pipeline runs npm audit on every build

4. Authentication Methods

Password-Based Authentication

Risks:
- Users reuse passwords across sites
- Weak password choices
- Phishing attacks

Modern approach: Combine with MFA

Multi-Factor Authentication (MFA)

"Something you know" (password)
+ 
"Something you have" (phone/authenticator)
+
"Something you are" (fingerprint/face)

Implementations:
- TOTP (Time-based One-Time Password): Google Authenticator
- SMS: Text message codes
- Email: Click verification link
- Hardware tokens: USB security keys
- Biometrics: Fingerprint, face recognition

OAuth 2.0 - Delegated Authentication

User → sign in with Google/Facebook
      → Redirected to provider
      → User grants permission
      → Redirected back with authorization code
      → App exchanges code for access token
      → App uses token to get user info

Advantages:
- No password shared with app
- Provider handles security
- User can revoke access anytime

Implementation:
- Use well-tested libraries (passport.js, auth0)
- Verify token signatures
- Use HTTPS only

5. Security Best Practices

Development Phase

// 1. Input Validation
function validateEmail(email) {
    const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!regex.test(email)) {
        throw new Error('Invalid email');
    }
    return email.toLowerCase();
}

// 2. Output Encoding
function escapeHtml(text) {
    const map = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#039;'
    };
    return text.replace(/[&<>"']/g, m => map[m]);
}

// 3. Use Security Headers
app.use((req, res, next) => {
    res.setHeader('Content-Security-Policy', 
        "default-src 'self'; script-src 'self'");
    res.setHeader('X-Frame-Options', 'DENY');
    res.setHeader('X-Content-Type-Options', 'nosniff');
    res.setHeader('Strict-Transport-Security', 
        'max-age=31536000; includeSubDomains');
    next();
});

Deployment Phase

# 1. Environment Variables (never commit secrets)
export DB_PASSWORD="secure_password_here"
export API_SECRET="secret_key"

# 2. SSL/TLS Certificates
# Use Let's Encrypt (free) or paid CAs

# 3. Firewall Configuration
# - Allow only necessary ports
# - Port 443 (HTTPS)
# - Port 80 (HTTP → redirect to HTTPS)
# - Block everything else by default

# 4. Regular Updates
apt update && apt upgrade  # Linux system updates
npm audit fix             # Update dependencies
docker pull latest        # Update containers

6. Compliance Standards

GDPR (General Data Protection Regulation)

Key Requirements:
- User consent for data collection
- Right to access personal data
- Right to deletion ("right to be forgotten")
- Data breach notification (72 hours)
- Data Privacy Officer for large orgs
- Fines: up to €20 million or 4% revenue

Implementation:
- Implement privacy controls
- Data retention policies
- Secure deletion procedures

CCPA (California Consumer Privacy Act)

Key Requirements:
- Disclose data collection practices
- User right to know what data collected
- User right to delete data
- User right to opt-out of data sales
- Fines: up to $7500 per violation

Applies to: Companies processing CA residents' data

PCI DSS (Payment Card Industry)

Applies: Any system handling credit cards

Key Requirements:
- Encryption of cardholder data
- Secure network architecture
- Access controls
- Regular security testing
- Incident response plan
- Fines: $5,000-$100,000 per month if non-compliant

7. Incident Response

Incident Response Phases

1. Detection
   - Monitor for anomalies
   - Set up alerts
   - Log everything

2. Analysis
   - Determine scope (how many users affected)
   - Identify root cause
   - Classify severity

3. Containment
   - Stop the bleeding
   - Isolate affected systems
   - Prevent further damage

4. Recovery
   - Restore from backup
   - Apply fixes/patches
   - Gradually bring systems online

5. Communication
   - Notify affected users (required by law)
   - Update regulators
   - Be transparent
   - Explain steps being taken

6. Post-Incident Review
   - Document what happened
   - What could have prevented it
   - What will change to prevent recurrence

What to Do When Breached

DO:
✓ Engage security forensics team
✓ Preserve evidence
✓ Notify legal team
✓ Inform affected users
✓ Report to regulators (if required)
✓ Monitor credit bureaus
✓ Offer credit monitoring

DON'T:
✗ Cover it up
✗ Delete evidence
✗ Communication without legal advice
✗ Assume hackers are gone after one patch

8. Developer Security Checklist

Before deploying to production:
□ All user inputs validated
□ All outputs encoded/escaped
□ SQL queries parameterized
□ Sensitive data encrypted
□ No hardcoded credentials
□ Security headers configured
□ HTTPS enabled
□ Passwords hashed (bcrypt/Argon2)
□ Rate limiting implemented
□ Authorization checks in place
□ Dependencies updated (npm audit)
□ No debug mode enabled
□ Logging doesn't contain sensitive data
□ CSRF protection enabled
□ Security.txt configured
□ Regular backups enabled
□ Incident response plan documented

Ongoing:
□ Security updates applied
□ Penetration testing scheduled
□ Code reviews always occur
□ Security training for team
□ Monitoring and alerting active

Key Takeaways

  1. Security is everyone's responsibility - Not just security teams
  2. Assume breach will happen - Design for recovery
  3. Defense in depth - Multiple layers of security
  4. Keep systems updated - Most exploits target outdated software
  5. Follow OWASP guidelines - Well-researched best practices
  6. Use proven libraries - Don't roll your own crypto
  7. Security through obscurity fails - Assume attackers know your architecture
  8. Monitor and respond - Detect and respond quickly to incidents

Security is an ongoing journey, not a destination. Stay vigilant!