Six Questions to Ask About Your Laravel Application's Security

Six Questions to Ask About Your Laravel Application's Security

Most of what's written about application security is aimed at the people writing the code. If you own a Laravel application and pay somebody else to look after it, that's not much help. You still need to know whether it's being looked after.

These are six questions with factual answers. You don't need to understand the answers technically — you need to hear a specific one, because the failure mode we see most often isn't a measure done badly. It's a measure nobody has got to yet, and vagueness is what that sounds like.

Every one of these is something we do on our own systems, so none of it is a standard nobody meets.

1. Is a password enough to get into the admin?

If the answer is yes, that's the one to fix first. An admin panel that only ever asks for a password is one leaked, reused, or guessed password away from being open, and passwords leak constantly through breaches at unrelated services.

A good answer: two-factor is required, not optional. There's a difference — optional means available to people who bother.

What to listen for: "we have it available" or "the passwords are strong". Neither answers the question.

Ask this one alongside it: how many people can sign in, and does that list match who works there now? Old accounts belonging to people who left are one of the most common ways in, and they cost nothing to remove.

2. Does anything actually read the logs?

Almost every Laravel application records failed sign-ins somewhere. Far fewer have anything that looks at what was recorded.

This is the gap we'd flag first in most applications, because it looks solved from the outside. A password-guessing run against your admin panel would be written down faithfully, in order, with timestamps — and noticed by nobody, which puts you in exactly the position of not having recorded it.

A good answer: somebody or something gets a message when the pattern looks wrong, and there's a real example of it having happened.

Two things separate an alert people act on from one they learn to ignore. Repeat them back if the answer you get is vague. A successful sign-in on its own should never send an alert — that's you or your developer arriving at work, and a daily email trains everybody to ignore the channel. But a successful sign-in in the same window as a run of failures should always alert, because that's the shape of somebody getting in. And a sustained attack has to produce one message, not one per check, or the warning gets buried in its own volume and your mail provider starts blocking the sender.

3. If the server was gone tonight, what would you restore from?

Not "do you have backups". Ask where they are, when the last one was made, and whether anyone has ever restored one.

A good answer: a copy exists somewhere other than the server it came from, made within the last day or so, and somebody has actually restored it and looked at the result.

Three specifics to press on, because this is where confident answers are most often wrong:

  • Off the machine. A backup on the same server protects you from a bad deploy and from nothing else. The day the server is what you lost is the day these exist for.
  • Encrypted before it leaves. Your database holds names, email addresses, messages, and probably IP addresses. Email isn't encrypted end to end, so a plain database archive attached to an email is customer data sitting in at least two mailboxes. Ours are encrypted before anything leaves the machine, and the plain copy stays behind.
  • The key isn't only on the server. An encryption key kept solely in the application's configuration file protects nothing once the server is what you lost. It belongs in a password manager as well.

What to listen for: "it's all backed up automatically." By what, to where, and when did anyone last look?

A backup nobody has restored isn't a backup. It's a file with a reassuring name. The only way to know is to restore one somewhere safe and read a few rows out of it — which is a test you can run once a year and sleep better for.

4. What happens if somebody submits the contact form ten thousand times?

Every public form on your site writes to your database and usually sends at least one email. Without a limit, an afternoon of automated submissions fills your tables, buries any real inquiry that arrived that day, and gets your sending domain flagged as a spam source. That last one can take weeks to undo and affects every email your business sends, including invoices.

A good answer: each public form has a limit, and it's low. Ours allow a handful a minute from the same source — far more than any person fills in a form, far less than makes flooding worthwhile.

A detail that tells you somebody thought about it: what a blocked visitor sees. A person who double-clicked should get the form back with a sentence explaining, not a bare error page they can do nothing with.

5. What is the browser being told?

A handful of HTTP headers instruct the browser to refuse things it would otherwise permit — framing your site inside somebody else's, guessing at file types, leaking your internal URLs to sites you link out to.

Most of them take five minutes. The one that takes real work is the Content Security Policy, which restricts where the page is allowed to load code from and where it's allowed to send data. It's the measure that limits the damage when something does get injected.

A good answer: they're set, and somebody can tell you what the policy allows and why.

When we did this on our own site, the reports found something we hadn't known about: an admin page was sending the signed-in user's initials to a third-party service on every load, through a framework default nobody had chosen. That's the kind of thing this finds.

Related, and ask this one directly: does the admin area render anything the public typed? Contact form messages, submitted URLs, uploaded file names. Those are read by somebody signed in with full permissions, which makes them the most sensitive text in the application.

6. How long do you keep data you don't need?

Applications collect more than the form asked for. IP addresses, browser strings, and referring URLs get stored alongside submissions almost by default.

There are reasons to keep that briefly — checking whether a burst of submissions came from one place, mostly. There's rarely a reason to keep it for years. Data you don't hold can't leak, can't be subpoenaed, and doesn't appear in a breach notification.

A good answer: there's a schedule, it runs automatically, and somebody can say what it removes and after how long. Ours blanks the network details on old inquiries while keeping the inquiry itself.

What the answers add up to

None of these is exotic and none is expensive. What they measure is whether anybody has spent an afternoon on the parts of your application that don't produce features.

If you get six specific answers, your application is in better shape than most. If you get six reassuring ones with no detail behind them, you've learned something useful, and it's fixable — this is a few days of work on a typical application, not a rebuild.

We do this kind of review on Laravel applications and the web applications that grew out of them, including ones whose original developer is long gone. If you'd like somebody to answer these six about your own system, tell us what you're running.

Frequently asked questions

I'm not technical. Can I really assess this myself?

You can assess whether the work has been done, which is the thing most often missing. Every question here has a factual answer — either two-factor sign-in is required or it is not, either somebody gets an email when sign-ins fail or nobody does. You are not judging the quality of the code, you are finding out whether anyone has thought about it.

Our application is small and nobody knows about it. Does this apply?

Automated scanning does not care whether anyone knows about you. Login pages and admin paths get probed constantly by scripts working through lists of addresses. Small applications are targeted the same way as large ones — the difference is that they usually have nobody watching.

What if the developer who built it is no longer available?

That is the most common version of this problem, and the questions still work — you are asking about the state of the application rather than about a person. Someone can answer all six by looking at the code and the server, and the answers tell you what needs doing before anything else.

Work with Emyrix

Working on something like this?

We build and maintain Laravel applications — customer portals, internal tools, integration layers, and inherited codebases nobody wants to touch. If you've got a performance or security problem you'd rather not sit on, tell us what's going on and we'll tell you what we think.