103 companion flashcards · AI-assisted study content · Open the deck →
This deck walks you through the core ideas behind modern software security, with a strong focus on web application threats and defenses. You'll encounter questions about common vulnerability classes like cross-site scripting, SQL injection, and cross-site request forgery, along with the protective techniques developers use to counter them, such as parameterized queries and input sanitization. Beyond attack patterns, the cards also cover foundational concepts like authentication versus authorization, OAuth 2.0 flows, JWTs, and how HTTPS and TLS certificate chains establish trust on the web.
The deck is well suited for anyone learning or reviewing application security fundamentals, whether you're a student, a developer aiming to write more secure code, or someone preparing for a technical interview that touches on security topics. If you're newer to the subject, the cards can serve as a structured overview of the landscape; if you already have some experience, they're a handy way to refresh terminology and make sure you can articulate each concept clearly.
To get the most out of these flashcards, try to think about the "why" behind each term, not just the definition. When a card mentions a vulnerability, ask yourself how a defender would recognize or prevent it. Spacing your review across several short sessions rather than cramming will help these concepts move into long-term memory, and pairing the cards with a small hands-on exercise, like spotting an XSS pattern in sample code, can make the material stick much more effectively.
The Open Worldwide Application Security Project (OWASP) publishes a regularly updated list of the ten most critical web application security risks, and the 2021 edition includes broken access control, cryptographic failures, injection, insecure design, security misconfiguration, vulnerable components, authentication failures, data integrity failures, logging failures, and server-side request forgery (SSRF). Many of these risks manifest as well-known attack patterns that developers must learn to recognize and prevent. Cross-Site Scripting (XSS), for instance, lets an attacker inject malicious scripts into pages viewed by other users, and it appears in three forms: reflected XSS, where input from a request is bounced straight back in the response without encoding; stored XSS, where the payload is persisted on the server (for example, in a comment database) and served to every viewer; and DOM-based XSS, where vulnerable client-side JavaScript reads untrusted data from sources like location.hash and writes it to the page using unsafe APIs such as innerHTML or document.write.
Cross-Site Request Forgery (CSRF) takes a different angle: it tricks a victim's browser into issuing an unwanted request to a site where they are already authenticated, such as a hidden form posting to a banking endpoint. Defenses include per-request tokens, the SameSite cookie attribute, and checks on the Origin and Referer headers. SQL injection is another classic danger, occurring when untrusted input is concatenated into SQL queries and allowing attackers to run arbitrary statements like the infamous ' OR '1'='1' trick. The primary defense is parameterized queries, sometimes called prepared statements, which separate SQL code from data using placeholders so that the database engine never interprets user input as executable code. The same general principle applies to command injection, where unsanitized input reaches a system shell: developers should avoid invoking operating system commands entirely when possible, prefer language-native APIs, and otherwise pass arguments as separate array elements rather than as an interpolated string.
Beyond these, several other vulnerabilities round out the threat landscape. Broken access control, the top item on the OWASP list, lets users act outside their intended permissions, and Insecure Direct Object References (IDOR) are a particularly common variant, where simply changing a numeric ID in a URL exposes another user's data. SSRF tricks the server itself into making requests to unintended destinations, often internal services or cloud metadata endpoints, and can be mitigated with allowlists and blocked private IP ranges. Clickjacking, also called UI redressing, overlays a transparent iframe on a legitimate page so users click on hidden elements instead of what they see, and is blocked using X-Frame-Options or a Content-Security-Policy frame-ancestors directive. Security misconfiguration, meanwhile, is a broad category that includes unchanged default credentials, unnecessary features, missing security headers, verbose error messages, and unpatched software, all of which can be addressed through automated scanning, minimal installations, and infrastructure-as-code practices.
Secure communication over the web depends on Transport Layer Security (TLS), the protocol underlying HTTPS. During the TLS handshake, the client proposes supported cipher suites, the server replies with its digital certificate and a chosen cipher, the client validates that certificate against trusted certificate authorities (CAs), and the two sides use asymmetric cryptography to derive a shared secret. From that point onward, all traffic is protected by faster symmetric encryption. The trust model is hierarchical: a self-signed root CA sits at the top, intermediate CAs are signed by roots, and server certificates are signed by intermediates. Browsers walk up the chain to confirm each link, and certificate pinning can further restrict which authorities are accepted for a given domain, though Certificate Transparency has largely replaced HTTP Public Key Pinning in modern deployments.
Cryptography itself comes in two principal flavors. Symmetric encryption uses the same key for both encryption and decryption and is favored for bulk data because of its speed; examples include AES and ChaCha20. AES operates on 128-bit blocks with key sizes of 128, 192, or 256 bits, and modern recommendations prefer AES-256-GCM because the Galois/Counter Mode provides authenticated encryption, delivering both confidentiality and integrity in one step. Asymmetric encryption, in contrast, pairs a public key with a private key and is used for key exchange and digital signatures; RSA and elliptic-curve cryptography are the most common algorithms. TLS cleverly combines both worlds: asymmetric crypto establishes a session key, and symmetric crypto then carries the bulk traffic efficiently. A digital signature follows a similar pattern: the sender hashes the message, encrypts that hash with a private key, and the recipient verifies by decrypting with the corresponding public key and comparing hashes. This proves both authenticity (who signed it) and integrity (the message was not altered), and the technique underpins everything from TLS certificates to signed JWTs to code signing.
Passwords require a different approach because they must be protected in a form that is never recoverable. Hashing provides a one-way transformation: given a hash, you cannot in general recover the original input, but you can re-hash a candidate password and compare. Fast general-purpose hashes like MD5 and SHA-256 are unsuitable for passwords because attackers can compute billions of guesses per second, so the field uses deliberately slow, password-specific functions. Bcrypt, based on the Blowfish cipher, includes automatic salting and a configurable work factor that can be increased as hardware grows faster; its output looks like $2b\(12\)salt...hash.... Argon2, the winner of the 2015 Password Hashing Competition, is even more flexible, with Argon2id (a hybrid variant) recommended for general use and tunable parameters for time, memory, and parallelism that resist both GPU and ASIC attacks. Salting is what makes these schemes resistant to rainbow table attacks: precomputed tables of hash-to-password mappings become useless when every user has a unique random salt mixed into their hash. It is also worth keeping three related concepts distinct: encoding (such as Base64 or URL encoding) is purely for compatibility and offers no security; encryption is reversible with a key; and hashing is one-way. Confusing these is a frequent source of vulnerabilities.
Authentication and authorization are often conflated, but they answer fundamentally different questions. Authentication verifies who you are, typically through something you know (a password or PIN), something you have (a phone or hardware token), or something you are (a fingerprint or face). Authorization, on the other hand, decides what you are permitted to do once your identity is known, using roles, permissions, and access control lists. Authentication always comes first, and a common pattern is multi-factor authentication, which combines at least two of those independent factor types so that compromising one alone is not enough to impersonate a user; common implementations include time-based one-time passwords (TOTP) and the WebAuthn/FIDO2 standards.
OAuth 2.0 is an authorization framework, not an authentication protocol, designed to let third-party applications act on a user's behalf at another service without ever handling that user's primary credentials. Several grant types suit different scenarios: the Authorization Code flow is the most secure and is used by server-side applications; PKCE extends this for single-page apps and mobile clients; the Client Credentials grant handles machine-to-machine communication; and Refresh Tokens let clients obtain new access tokens without re-prompting the user. In the Authorization Code flow, the user is redirected to an authorization server, authenticates there, grants consent, and is redirected back with a short-lived authorization code that the application exchanges server-to-server for an access token. Because tokens never traverse the browser in plaintext, this approach resists interception. JSON Web Tokens (JWTs) are a popular token format with three Base64Url-encoded parts: a header declaring the algorithm, a payload of claims such as user identity and expiration, and a signature that binds them together using HMAC or RSA. JWTs are stateless because the server can verify them without storing session state, but they carry common pitfalls: accepting alg: "none", storing them in localStorage where XSS can steal them, skipping signature validation, omitting an exp claim, embedding sensitive data (the payload is only encoded, not encrypted), and failing to provide a revocation mechanism.
OpenID Connect (OIDC) layers authentication on top of OAuth 2.0. Where OAuth answers "what can this application access on the user's behalf?", OIDC answers "who is this user?" by returning an ID token (typically a JWT) plus a /userinfo endpoint that exposes standardized claims such as openid, profile, and email. Together, these protocols form the backbone of modern federated identity: OAuth 2.0 for delegated authorization, OIDC for federated authentication, JWTs as a compact token format, and MFA layered on top to strengthen the initial authentication step. Secure session management complements these protocols on the server side by generating cryptographically random session identifiers, setting cookies with HttpOnly, Secure, and SameSite attributes, enforcing idle and absolute timeouts, regenerating the session ID after login to prevent session fixation, and invalidating sessions on logout.
Browsers enforce a powerful default protection called the Same-Origin Policy, which prevents scripts loaded from one origin from reading resources served by a different origin. Two URLs share an origin only when they match in protocol, host, and port, so https://example.com:443 and http://example.com:80 are technically distinct origins. This default isolation is essential because it stops a malicious page from quietly reading a user's data on another site, but it is also rigid, so Cross-Origin Resource Sharing (CORS) exists as a controlled escape hatch. CORS lets servers declare, via response headers, which origins may access their resources, which HTTP methods are permitted, which custom headers are allowed, and whether credentials (such as cookies) may be included. Browsers send a preflight OPTIONS request to verify permissions before sending the actual request, so a misconfigured CORS policy can quietly turn into a significant authorization bypass.
Content Security Policy (CSP) is another defense layer, configured via an HTTP response header that tells the browser which sources of content are allowed to load. By setting directives such as default-src 'self', script-src 'self' cdn.example.com, and style-src 'self' 'unsafe-inline', a site can block inline scripts, restrict script origins, and dramatically shrink the attack surface available to an XSS payload. CSP nonces go further: a server generates a unique random token for each page load, declares it in the policy with script-src 'nonce-abc123', and tags only those specific inline scripts with the matching nonce attribute. Because the nonce changes on every request, an attacker who injects a script cannot know the right value, and the browser refuses to execute anything that lacks it. CSP also helps defend against clickjacking through the frame-ancestors directive, which replaces the older X-Frame-Options header.
A complete browser-hardening strategy relies on a family of HTTP security headers working together. Strict-Transport-Security (HSTS) instructs the browser to use HTTPS for a domain for a specified period, even if the user types http://, which prevents SSL stripping attacks; the preload flag adds the domain to a list hardcoded into major browsers. X-Content-Type-Options: nosniff blocks MIME sniffing, denying browsers the freedom to reinterpret responses as a different content type. The legacy X-XSS-Protection header turns on older browser XSS filters, while Referrer-Policy controls how much URL information travels in the Referer header to other sites. Permissions-Policy (formerly Feature-Policy) restricts which powerful browser features such as camera, microphone, or geolocation a page may use. Finally, the SameSite cookie attribute has become one of the simplest yet most powerful CSRF mitigations: Strict sends the cookie only for same-site requests, Lax (the default in modern browsers) sends it for top-level navigations but not embedded requests, and None always sends it but requires the Secure flag. Together, these headers create layered, defense-in-depth protection at the browser boundary.
Sessions, secrets, and rate limits form the operational backbone of a secure application. Secure session management begins with generating session identifiers using a cryptographically secure random number generator so that IDs cannot be guessed or predicted. Cookies that carry these identifiers must be marked HttpOnly (so JavaScript cannot read them, mitigating XSS theft), Secure (so they only travel over HTTPS), and SameSite (so they are not sent on cross-site requests). Best practice also calls for both idle and absolute session timeouts, regeneration of the session ID immediately after a successful login to prevent session fixation attacks, and proper invalidation on logout. Storing actual session data on the server rather than inside the cookie itself makes revocation and anomaly detection far easier.
Secrets management addresses the everyday reality of API keys, database passwords, certificates, and tokens that an application needs to function. The cardinal rule is to never hardcode secrets into source code or commit them to a public repository. Instead, applications should retrieve secrets at runtime from environment variables or, better, from a dedicated vault such as HashiCorp Vault or AWS Secrets Manager. Secrets should be rotated regularly, access to them should be audited, and configuration files containing them should be excluded through .gitignore. The same discipline applies to API keys specifically: they should never be embedded in client-side code, should be scoped to the minimum permissions required, should have expiration dates, and should differ between development and production. Separate keys per environment also make it easier to revoke one without disrupting everything else, and usage monitoring can spot anomalies that suggest a key has leaked.
Rate limiting protects applications and APIs from abuse by restricting how many requests a client can make within a given time window. It defends against brute-force login attempts, distributed denial-of-service attacks, and unfair usage, and overloaded servers respond with HTTP 429 Too Many Requests and a Retry-After header telling the client when to try again. Several algorithms are in common use: the fixed-window counter resets on a schedule, the sliding window smooths traffic across boundaries, and the leaky bucket drains requests at a steady rate. The token bucket variant is especially popular because it allows brief bursts up to the bucket's capacity while smoothing long-term rate, with tokens added at a fixed rate and each request consuming one; if the bucket is empty, the request is rejected. Services such as AWS API Gateway and Stripe use this approach because it strikes a good balance between simplicity, fairness, and the ability to absorb legitimate spikes.
Beyond any single technology, robust software security rests on a small number of enduring design principles. The principle of least privilege holds that every user, program, and process should operate with only the minimum permissions necessary to perform its function. Applied at the database tier, this means a web application's DB account should be able to run only the queries it needs, not arbitrary administrative operations. Applied at the infrastructure tier, container processes should run as non-root users, IAM roles should grant only the AWS actions required, and API tokens should be narrowly scoped. The benefit is containment: when something goes wrong, least privilege dramatically shrinks the blast radius of the breach.
Defense in depth is the companion idea: no single control is ever considered sufficient, and security is built up from many overlapping layers. Network-level protections such as firewalls, virtual private networks, and intrusion detection systems shield the perimeter; application-level controls like input validation and authentication protect the user-facing surface; data-level measures including encryption at rest and strict access controls protect information even if attackers reach the database; physical safeguards keep servers locked away; and continuous monitoring through logging and alerting ensures that anomalies are detected quickly. Man-in-the-middle attacks illustrate the model well: HTTPS/TLS encrypts traffic, HSTS prevents downgrade attempts, certificate pinning and chain validation reject rogue certificates, and secure Wi-Fi like WPA3 protects the underlying link. Layering means an attacker must defeat every control, not just one.
Finally, the everyday disciplines of input validation and output encoding deserve emphasis because they are the front line against injection attacks. Input validation verifies that user-supplied data matches expected format, type, length, and range before processing. The allowlist approach, accepting only known-good patterns, is far stronger than the denylist approach of trying to reject known-bad input, and validation must run on the server even when it also runs on the client for user experience. Output encoding is the other half: it transforms data for safe display in a specific context, whether HTML encoding for web pages, URL encoding for links, or JavaScript encoding for script bodies. The two work together: validation keeps bad data out in the first place, and encoding protects the system when some bad data slips through or was already present in storage. Combined with rate limiting, secrets management, secure session handling, and the broader defensive mindset, these principles turn security from a checklist of features into a continuous practice woven throughout the software development lifecycle.
Access-Control-Allow-Origin: allowed originsAccess-Control-Allow-Methods: allowed HTTP methodsAccess-Control-Allow-Headers: allowed headersAccess-Control-Allow-Credentials: allow cookiesOPTIONS) check permissions before the actual request.Strict-Transport-Security (HSTS): force HTTPSContent-Security-Policy: control resource loadingX-Content-Type-Options: nosniff: prevent MIME sniffingX-Frame-Options: prevent clickjackingX-XSS-Protection: legacy XSS filterReferrer-Policy: control referrer informationPermissions-Policy: control browser featuresDrill this topic
103 flashcards on Software Security — free, no signup needed to start.
Study Software Security flashcardsLearnWiki pages are generated with AI assistance from LearnCoachAssist's reviewed study catalog and may contain errors — verify anything critical against your course materials.