Ruby on Rails Module 10
Securing Rails applications interview questions
Interview questions on securing Rails applications: short warm-ups, then what each harder question tests, the first step of a good answer and its follow-ups.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher
What is the difference between CSRF and XSS, and which one does the authenticity token stop?
Answered in the lesson Rails security defaults: CSRF, XSS and SQLi
-
Fresher to mid
A Rails log shows
password: "[FILTERED]"but also anotesfield with the plain textwrote the password down. Why does the filter hide one and not the other?Answered in the lesson Credentials, secrets and Active Record encryption
-
Fresher
What do
assume_sslandforce_ssleach do behind a proxy that ends TLS?Answered in the lesson HTTPS, security headers, CSP and host checks
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Mid to senior
Kaksha serves Turbo forms to browsers and a JSON API to a mobile app that sends a bearer token. A teammate adds skip_forgery_protection to the whole API controller. Say which requests need the authenticity token, which do not, and what you would change.
- What it tests
- Whether the candidate ties CSRF to credentials that a browser sends by itself, not to JSON or to HTTP verbs, and can scope an exemption narrowly instead of cutting a hole in a controller.
- First step
- Ask how each request proves who the caller is. A browser attaches its cookie to any request it makes, so a forged request carries it; a bearer token is added by code the caller controls. Decide per authentication mechanism, then look for an endpoint that accepts both.
- Follow-ups
-
- What changes if the same endpoint also accepts the session cookie?
- Why is a controller that inherits from ActionController::API a better home than a skipped filter?
- How would you test that the browser forms still refuse a POST without a token?
- What does Turbo send, and where does it read the value from?
From the lesson Rails security defaults: CSRF, XSS and SQLi
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
Assess this action: Notice.where("title LIKE '%#{params[:q]}%'").order("#{params[:sort]} #{params[:dir]}"). Name each problem in order of risk, write the fixed action, and describe a check that fails on the original without sending anything hostile.
- What it tests
- Whether the candidate separates values from names, binds the values, uses an allowlist for the names, and tests with ordinary input such as a surname with an apostrophe.
- First step
- Split the line into values and names. The search term is a value and can be bound. The sort key and direction are names, and nothing can bind a name. Choose binding for the first and an allowlist of keys you wrote for the second.
- Follow-ups
-
- Why does a placeholder not protect the order clause?
- What does Rails' own check on order accept, and why is that not an allowlist?
- How do you test the fix with an ordinary surname?
- What changes for a filter on several columns?
From the lesson Rails security defaults: CSRF, XSS and SQLi
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A pull request adds :role and :centre_id to the params.expect list of the profile update, because owners edit them in the same form that students use. Explain what is wrong, what you would ask for instead, and the test that proves the fix.
- What it tests
- Whether the candidate sees a permitted list as an allowlist for one actor and one action, and separates the owner action behind authorization from the student action.
- First step
- Ask who can reach the action. Every key on its list is a key that any of those callers can set by adding it to the request, whatever the form shows. Then ask which actor really needs each field.
- Follow-ups
-
- What does params.expect do with a key that is not on the list, and how would you notice?
- Would a role check inside the model make the wide list safe?
- How do you test that a student cannot set a field?
- When is a wider list acceptable?
From the lesson Rails security defaults: CSRF, XSS and SQLi
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
An alert at Kaksha says the production RAILS_MASTER_KEY may have been read by someone who should not have it. secret_key_base is one of the credentials. Rotate it in a way that fits the alert, and keep the next scheduled quarterly rotation of the same key running under its own clock.
- What it tests
- Whether the candidate separates an incident rotation from a scheduled one: a registered rotation keeps users signed in on a schedule, and a deploy with no rotation ends the old secret at once after a leak.
- First step
- Picture the two states. On a scheduled rotation the old secret must stay verifiable for the window you choose, so it stays registered as a rotation. On an incident it must stop working at once, so the new secret ships with no rotation. Decide which this alert is, then order the deploy, the note to users and the retire step to match.
- Follow-ups
-
- Which two registrations does a Rails app need for a scheduled rotation, and what does each cover?
- A verification link made with the old secret is sent on the morning of the rotation. What happens on each path?
- How do you know the window has emptied enough to retire the old secret in a routine rotation?
- What has to happen to the column encryption keys, which this rotation does not touch?
From the lesson Credentials, secrets and Active Record encryption
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
Kaksha stores a guardian's phone, address, PAN card number and a free-text note. The team is adding Active Record Encryption. Decide which columns to encrypt and which shape to pick for each, and defend the choices against the shape you did not take.
- What it tests
- Picking deterministic or non-deterministic per column from the question "is this column queried on", knowing what each shape leaks, and accepting that a column that is public is better left plain.
- First step
- List what each column does in the app. The phone is a support lookup. The address is a free-text field nobody searches on. The PAN is matched against a tax filing once a year. The note is free text staff write for context. Then match each against the two trade-offs: whether find_by must work, and whether the pattern of repeated values would say something to someone who reads a database leak.
- Follow-ups
-
- What exactly leaks in the row set when a column is deterministic?
- A support screen searches by the last four digits of the phone. What breaks, and how do you serve the search?
- How do you backfill an encrypted column on a live table without a maintenance window?
- When would you choose to leave a sensitive column plain anyway?
From the lesson Credentials, secrets and Active Record encryption
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 5 minutes
-
Mid to senior
A Kaksha developer pushes a branch to the public mirror of the app repo and realises after fifteen minutes that the credentials key file is in the diff. The branch has not been merged. Lay out the response for the next 24 hours.
- What it tests
- Treating the leak as "everything the file guarded is public now", not just "a key is in a public commit"; rotating the right secrets in the right order, and knowing which traces of the key cannot be rewritten away.
- First step
- List what the credentials key opens: config/credentials.yml.enc, which holds secret_key_base and every API key the file carried, in every version git has. Treat each as leaked. Then order the work by what shortens the attacker's window most: a new credentials key and new values for secret_key_base and the external keys first, the file off the branch second, and a note to users last.
- Follow-ups
-
- Why is "git push -f with the file removed" not enough?
- Which Active Record Encryption keys are affected, and which are not?
- What does the incident timeline look like for the rotation of secret_key_base here, compared with a scheduled one?
- How does a secret scanner help after the fact, and how does it not?
From the lesson Credentials, secrets and Active Record encryption
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
Your Rails 8.1 app has scaffold-style views with inline style attributes, an import map and Turbo. Walk through putting a strict Content Security Policy on it without breaking a page, from the first header to enforcement.
- What it tests
- Whether the candidate rolls a policy out in stages, knows what a nonce-based policy needs from import maps and Turbo, and finds the inline styles that a strict style policy refuses.
- First step
- Start from a policy that denies everything and add only what the pages use. Ship it in report-only mode first, so violations are reported while nothing breaks. Then list what is inline, fix those places, and only after the reports go quiet switch the header to enforcing.
- Follow-ups
-
- Which directives does Turbo Drive need beyond script-src and style-src, and why?
- How do you prove, without a browser, that every script and style tag carries the nonce?
- What does the browser-side check add that a request test cannot?
- When is a hash a better choice than a nonce, and when is plain 'self' enough?
From the lesson HTTPS, security headers, CSP and host checks
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Senior to staff
The generated CSP initializer sketches a nonce generator built from request.session.id. Argue for or against keeping it, and say what you would use instead and what that choice costs.
- What it tests
- Whether the candidate knows what a nonce must guarantee, can spot a value that repeats for a session or is empty on the first request, and can name the caching cost of a fresh value on every response.
- First step
- State the property first: a nonce is only useful if an attacker cannot guess the value before the response is sent. Then test the session-id generator against it on three requests of one session, and compare with a random value made for each response.
- Follow-ups
-
- What does the response carry on the very first request of a session with the session-id generator?
- What does a random nonce per response cost for conditional GET and for page or fragment caches?
- How does a hash-based policy avoid that cost, and what does it demand of the inline code?
- How would you test the property in CI?
From the lesson HTTPS, security headers, CSP and host checks
Model answer, Pro.In the answer:
- Model answer
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
After you set config.hosts and config.force_ssl in production, the load balancer marks every instance unhealthy. Diagnose it with requests, fix it, and explain what config.hosts protects against.
- What it tests
- Whether the candidate can reason about which middleware answers first, reproduce both refusals with one request each, and place the exclusions where they belong without opening the app to every Host name.
- First step
- Send the exact request the load balancer sends, with its Host value and over plain HTTP, and read the status. A 403 means the host check refused it, a 301 means the SSL redirect did. Both are middleware that run before the router, and each has its own exclusion.
- Follow-ups
-
- Which middleware runs first, the host check or the SSL redirect, and how would you confirm it?
- Why exclude /up instead of adding the load balancer's address to config.hosts, and when is one exclusion enough?
- How can a pattern for subdomains let a look-alike name through, and how do you test for it?
- What is DNS rebinding, and what does the host list stop?
From the lesson HTTPS, security headers, CSP and host checks
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
All Ruby on Rails interview questions · The Ruby on Rails track