Skip to main content

Security Interview Questions

Every question has a short model answer and a link to the lesson example that shows it in code. Levels: F = Fresher (0-2 yrs), M = Mid (3-5 yrs), S = Senior (6-9 yrs), A = Architect / Lead (10+ yrs).

Users and passwords

MWhy do we store a password hash instead of the password, and how is a hash different from encryption?concept

A hash is a one-way function: easy to compute from the password, practically impossible to reverse. At login, the app hashes the typed password and compares hashes, so the real password is never stored. Encryption can be reversed with a key, so a stolen key exposes every password.

AHow would you design roles and permissions so they can grow with the system?design

Start with users, roles, and a user-role junction, as in the SMS. When permissions get finer, add a permissions table and a role-permission junction, and check permissions rather than role names in code. Data rules, such as "a parent sees only their children", are checked separately from roles.

How to answer:

Describe role-based access control and its limits, then the step to permission-based checks. Use SMS examples: Teacher and Accountant roles, and the parent-sees-own-child rule as a data-level check. Mention the trade-off: more flexibility means more admin screens and more testing of who can do what.

Authentication

FWhat is the difference between authentication and authorization, and between 401 and 403?concept

Authentication answers "who are you?"; authorization answers "are you allowed to do this?". A request without a valid token fails authentication and gets 401 Unauthorized. A signed-in user who may not do something fails authorization and gets 403 Forbidden.

FWhat are the three parts of a JWT, and can anyone read its contents?concept

A header (the algorithm, such as HS256), a payload of claims (such as sub, name, role, exp), and a signature, separated by dots. The header and payload are only base64url encoded, so anyone can read them; the signature only stops anyone changing them. Never put passwords or secrets in claims.

FHow should an API store passwords?concept

As a slow, salted hash, never as text or with a fast hash alone. The SMS uses ASP.NET Core Identity's PasswordHasher: PBKDF2 with SHA-512, a random salt for each password, and 100,000 rounds. To sign in, the typed password is hashed the same way and compared.

MWhat does a fallback authorization policy do, and why use one?concept

It applies to every endpoint that has no authorization attributes of its own. Setting it to RequireAuthenticatedUser makes the API secure by default: a new endpoint that someone forgets to protect still needs a signed-in user. Public endpoints opt out with [AllowAnonymous], such as login.

MWhich token settings does the API check on every request, and why set ClockSkew?coding

The signature (with the signing key), the issuer, the audience, and the expiry time (exp and nbf). ClockSkew is a grace period for clocks that differ between servers; its default is 5 minutes, so an expired token would still work for 5 more minutes. The SMS sets it to 30 seconds.

MWhere should a JWT signing key be kept, and what happens if it leaks?concept

Outside source control: user secrets while developing, and environment variables or a key vault in production. Anyone with the key can create a valid token for any user, including an admin. If it leaks, replace it at once; every token signed with the old key then stops working. The SMS also refuses to start without a key of at least 32 characters.

SA security review finds that your login says 'unknown user' for one mistake and 'wrong password' for another. Why is that a problem, and how do you fix it?scenario

It tells an attacker which user names exist, so they can focus password guessing on real accounts. Use one message for every failure ("User name or password is wrong."), and make both paths do the same work: the SMS still verifies against a dummy hash when the user does not exist, so the response time does not give it away either. Add rate limiting and lockout against guessing.

How to answer:

Explain user enumeration through messages and through timing, then the fix for each, and the extra defences against password guessing.

SA parent reports that a report-card link works without signing in. How did it happen, and how do you stop it happening again?scenario

That endpoint was protected one by one with [Authorize], and someone forgot it. Fix it now, then change the design: a fallback policy that requires a signed-in user everywhere, with [AllowAnonymous] only where needed. Add an automated test that calls every endpoint without a token and expects 401, and check the logs for anyone who used the open link.

How to answer:

Cover the immediate fix, the design change that makes the mistake impossible, the test that guards it, and the investigation of possible data exposure.

AAccess tokens last 60 minutes. How would you let users stay signed in longer, and sign them out at once when needed?design

Keep access tokens short and add refresh tokens: long-lived, random, stored hashed on the server with the user and device, and exchanged for a new access token (rotating the refresh token each time). Signing out, or blocking a user, revokes their refresh tokens; for instant cut-off, keep a short deny list of token ids (jti) until they expire, or shorten access token lifetimes. Larger systems often move sign-in to an identity provider using OpenID Connect.

How to answer:

Separate access and refresh tokens, explain storage and rotation, cover revocation and its delay, and say when a dedicated identity provider is worth it.

Authorization

FWhat is role-based access control?concept

Users belong to roles (in the SMS: Admin, Principal, Teacher, Accountant, Parent), and permissions are given to roles instead of to each user. The API checks the user's roles, sent as role claims in the token, before running an action.

FA signed-in user calls an endpoint their role may not use. What status should the API return?concept

403 Forbidden: the API knows who they are, but they are not allowed. 401 is only for a missing, invalid, or expired token. The app treats them differently: 401 means "sign in", 403 means "not allowed".

FWhy is hiding a button in the app not enough to protect a feature?concept

Anyone can call the API directly, with a copied token and a tool such as curl or the browser's developer tools. Every permission must be checked on the server with [Authorize]; hiding buttons is only for a tidy screen.

MWhat is the advantage of named policies over [Authorize(Roles = "...")] lists?design

The controller says what kind of user it needs (such as Teaching), and the roles for each policy are defined in one place. Adding a role or changing a permission is one line, instead of a search through every controller where one forgotten copy becomes a security hole.

MA controller has [Authorize(Policy = "Staff")] and one action has [Authorize(Policy = "ManageSchool")]. Who may call the action?coding

Only users who pass both policies: every authorization attribute on the controller and on the action must pass. In the SMS, that is Admin and Principal, who are in both Staff and ManageSchool.

MIn what order does ASP.NET Core run authorization and model validation, and why does it matter?concept

Authorization runs first, then model binding and validation. A refused user gets 403 even with an invalid body, so they never learn what a valid request looks like. In the SMS, a teacher posting an empty admission got 403, while the principal got 400 with the field errors.

SThe office changes a teacher into an accountant, but for a while she can still take attendance and cannot open fees. Why, and what are the options?scenario

Her roles are inside her access token, and the API does not look them up again on each request, so the change only arrives with her next token (up to 60 minutes in the SMS). Options: accept the delay and ask her to sign in again; shorten token lifetimes; or check a revocation list or the user's current roles on each request, at the cost of a database or cache lookup.

How to answer:

Explain claims in self-contained tokens, then weigh the options by how fast changes must apply and what each costs.

SHow do you make sure no role can do more than it should, as an API grows?design

Secure by default with a fallback policy, named policies in one file, and a data-driven test table with one row per role and sensitive endpoint, including the refusals. In the SMS, each row is a role, a request, and the expected status, chosen so no row changes data. Review new write endpoints for their policy before merging.

How to answer:

Combine design (defaults and named policies), automated proof (the permission table), and process (reviews), and explain why refusals need tests as much as successes.

ASchools want to define their own roles and permissions without a new release. How would you design it?design

Move from fixed roles to permissions: store Permissions, RolePermissions, and UserRoles per school, and make endpoints require permissions (such as Attendance.Take) instead of roles. A custom authorization policy provider can create a policy per permission name, and a handler checks the user's permissions, loaded at sign-in into the token or cached per user. Keep a few built-in roles as templates, audit every change to permissions, and decide how fast changes apply.

How to answer:

Explain the move from roles to permissions, how ASP.NET Core can check them dynamically, where the data lives per school, and how changes propagate and are audited.

FWhat is IDOR (insecure direct object reference)?concept

A bug where an API checks that a user may use an endpoint but not whether the record in the request belongs to them. Changing an id in the URL then shows someone else's data, such as a parent opening another child's report card by changing the admission number.

FWhat is the difference between a role rule and a record rule?concept

A role rule needs only the token: "is this user a teacher?". A record rule also needs the record being reached: "is she the class teacher of section 20?" or "is this parent linked to ADM-2017-0003?". Record rules usually read the route and ask the database.

FShould an API answer 404 or 403 when a parent asks for a student who is not theirs?concept

403, and the same 403 when the student does not exist at all. If real records gave 403 and missing ones 404, the answers would reveal which ids exist. The SMS answers 403 for both, and only users allowed to see a record ever learn whether it exists.

MWhat are an authorization requirement and an authorization handler in ASP.NET Core?coding

A requirement (IAuthorizationRequirement) is a small class that states a rule and holds its settings, such as which staff roles count. A handler (AuthorizationHandler<TRequirement>) checks it and calls context.Succeed when the rule holds. A policy lists requirements, so controllers only name the policy.

MHow can an authorization handler know which record a request is about?coding

For endpoints, context.Resource is the HttpContext, so the handler can read route values (such as admissionNumber or sectionId) and the query string. The SMS handlers read them, then ask the database whether the user is linked to that record. For rules that need a loaded object, you can instead call IAuthorizationService.AuthorizeAsync(User, resource, policy) inside the action.

MWhy should a handler take the user's own ids from the token and not from the request?concept

Anything in the request (body, query, headers other than the token) can be changed by the user. The token is signed, so its claims, such as guardian_id or teacher_id, cannot be changed without breaking the signature. The SMS compares the route's record with the ids from the token.

SA parent reports seeing another child's marks by changing a number in the app's address. What do you do?scenario

Confirm and fix the endpoint first: add a record rule that checks the parent is linked to the student in the route. Then search every endpoint with an id in its route for the same gap, add permission tests that try other families' ids, and check logs for who reached records they should not have. Report the exposure as the school's policy requires.

How to answer:

Cover the immediate fix, the systematic search for the same bug, tests that prevent it returning, and the investigation and reporting of the leak.

SRecord checks add a database query to many requests. How do you keep them fast and correct?design

Keep each check a tiny EXISTS query on indexed links (StudentGuardians, ClassTeachers, SubjectAllocations). Put small, stable facts in the token at sign-in, such as the user's teacher or guardian id, but not lists that change often. Cache answers per user for a short time if needed, and invalidate when links change. Measure: in the SMS each check reads only a few rows.

How to answer:

Balance speed against freshness: what goes in the token, what is queried, what is cached, and how changes reach the checks.

AList endpoints (such as all invoices) must also show each user only their records. How would you design that across a large API?design

Record rules on single-record endpoints are not enough for lists: the query itself must filter. Build the filter from the user (for example, only students linked to this guardian) in one shared place, such as a data-access layer that always adds it, or database row-level security with SESSION_CONTEXT set per request. Test lists with users who own nothing, one record, and many records.

How to answer:

Separate single-record checks from list filtering, compare doing it in the data layer with database row-level security, and explain how to make it impossible to forget.

Auditing

FWhat are audit columns, and why are they useful?concept

Columns such as CreatedAt, CreatedBy, UpdatedAt, and UpdatedBy that record when and by whom a row was created and last changed. They answer "who changed this?" for disputed data such as marks and payments, and they protect staff who made correct changes.

FWhy must the 'changed by' user come from the token and not from the request body?concept

The client decides what is in the body, so anyone could write someone else's id. The signed token cannot be changed, and the server carries the user from it into the database without the client touching it.

FWhat is SESSION_CONTEXT in SQL Server?concept

A set of key-value pairs that belongs to one connection, set with sp_set_session_context and read with SESSION_CONTEXT(N'key'). Statements, triggers, and DEFAULT constraints on that connection can read it, which lets the API tell the database who the user is.

MA column has a DEFAULT, but new rows still get NULL. Why?scenario

The INSERT names the column and passes NULL, and an explicit value, even NULL, wins over the default. In the SMS, the Dapper inserts leave CreatedBy out, so DF_..._CreatedBy fills it from the session's user.

MHow can a singleton service know the current request's user in ASP.NET Core?coding

Inject IHttpContextAccessor (registered with AddHttpContextAccessor). It finds the current request's HttpContext from anywhere, so a singleton such as the SMS's HttpCurrentUser can read the user's "sub" claim each time it is asked, even though the user changes with every request.

MWhy set the session user in the connection factory instead of in each repository?design

Every connection comes from the factory, so one hook covers every repository, Dapper call, and transaction, and nobody can forget it. The SMS adds a StateChange handler that runs sp_set_session_context with @read_only = 1 as soon as a connection opens.

SWith connection pooling, could one user's id stay on a connection and be used by the next request?scenario

Not with SESSION_CONTEXT: SQL Server resets a pooled connection's session state before it is reused, so the next user starts with NULL. The SMS proves it with a test that opens a connection with user 42, then opens another from the same pool without a user and reads NULL. @read_only = 1 also stops code on the same connection from changing the id.

How to answer:

Explain pooling and the reset, show how you would prove it with a test, and mention read-only values.

SMarks were changed after results were published, and the audit log has old and new values but no user. How do you fix this for the future?scenario

The application connects with one shared login, and nothing tells the database who the person is. Pass the signed-in user to every connection (SESSION_CONTEXT), let the triggers and defaults read it, and stamp UpdatedBy in updates. Add a test that a change through the API records the user, and consider blocking changes to published results without a recorded reason.

How to answer:

Explain why the user was missing, describe the end-to-end fix, how to verify it, and a process rule for sensitive changes.

AHow would you design auditing for every important table in a large system?design

Decide what must be audited (who, when, what changed, from where), then choose a mechanism: triggers that write before-and-after values (as tr_Marks_Audit does), SQL Server temporal tables for full history, or change data capture feeding a separate audit store. Pass the user and request id on every connection, protect the audit data from changes (separate permissions, append-only), set retention rules, and give the office a way to search it.

How to answer:

Compare the mechanisms by detail, cost, and tamper resistance, and cover identity propagation, retention, and how people will use the audit data.

Rate limiting

FWhat is rate limiting, and what does it protect against?concept

Capping how many requests a caller may make in a period. It slows password guessing on sign-in, stops one client (or a buggy app in a loop) from taking everyone's share, and limits the damage of floods. The SMS allows 5 sign-ins per minute per address and 300 requests per minute per user.

FWhat should an API return when a request is rate limited?concept

429 Too Many Requests, with a Retry-After header saying how many seconds to wait when the limiter knows it, and a body in the API's usual error shape. Well-behaved clients wait instead of retrying at once.

FCompare the fixed window, sliding window, and token bucket limiters.concept

Fixed window: N requests per window, reset when it ends; simple, but bursts can cluster at the edge. Sliding window: N requests in any window, counted in segments; smoother. Token bucket: a bucket of N tokens refilled at a steady rate; allows short bursts with a steady average. The SMS uses a fixed window for sign-in and a token bucket for general traffic.

MWhat is a partition in ASP.NET Core rate limiting, and how do you choose the key?design

A partition is whose count a request uses, chosen by a key computed from the request. Before sign-in the only key is the client address; once signed in, the user id is fairer, because many users can share one address. The SMS uses "user:{sub}" when signed in and "ip:{address}" otherwise.

MWhere must app.UseRateLimiter() go in the pipeline, and why?coding

After UseAuthentication (and after routing, which minimal hosting adds early), so the limiter can see the signed-in user for per-user limits and the endpoint's [EnableRateLimiting] policy. Placed before authentication, every request would count as anonymous.

MWhy are rate-limit tests often flaky, and how do you avoid it?scenario

In tests every request comes from the same address and the suite makes many sign-ins, so a real limit is hit at random. Raise the limits in the shared test setup, and test the limiter on purpose with a separate server configured with small limits, as the SMS's RateLimitTests does.

SShould you protect sign-in with account lockout or with rate limiting?design

Lockout blocks the account after N failures, which also lets an attacker lock a real user out on purpose. A rate limit per address slows the attacker's address without touching the user, but a guesser with many addresses gets N guesses each. Combine them: a per-address limit first, a softer per-account protection (delays or a long lockout only after many failures), and alerts on repeated failures.

How to answer:

Compare who each defence slows down, how each can be abused, and propose a layered design.

SAt 8:00 every teacher signs in from the school's one network address and many get 429. What do you change?scenario

The sign-in limit is per address, and the whole staff room shares one. Raise the per-address sign-in limit for that school's deployment (it is configuration), and keep guessing slow with a per-account protection, such as a short lockout or growing delays per user name, plus alerts. Check the rejection logs to confirm the cause first.

How to answer:

Diagnose from the logs, explain why the partition key causes it, and give a fix that keeps the security goal.

AThe API runs on several servers behind a load balancer. How do you make rate limits correct across all of them?design

The built-in limiter counts in each server's memory, so N servers allow roughly N times the limit. Options: a gateway or reverse proxy that limits in one place before the servers; a shared store (such as Redis) that all servers count in; or dividing each server's limit by the number of servers as an approximation. Keep per-user limits in the API, where the user is known, and coarse per-address limits at the edge.

How to answer:

Explain why in-memory counts multiply, compare edge limiting, shared counters, and approximations, and say which limits belong where.