Ahosting Logo
Knowledge Base

WooCommerce Store Security Best Practices

A store compromise is a data breachWhat the store holds· customer names and addresses· order histories· account credentialsThe decision that limits exposure· do not store card details· let the gateway hold them, hosted or tokenised· so a compromise cannot expose what you never hadThe restTwo factor on every administrator, updates applied promptly, individual accounts rather thanshared ones, and backups you have actually restored.

A WooCommerce store holds customer names, addresses, order histories and account credentials. That changes the calculation from an ordinary WordPress site: a compromise here is a data breach with legal consequences, not just a defaced page.

The good news is that the defences are the same ones, applied properly. Almost every store compromise starts with an outdated plugin.

Updates, and specifically the ones people delay

Outdated plugins are the leading cause of compromised WordPress sites, and the gap between a vulnerability becoming public and being exploited at scale is measured in hours.

Stores have a genuine reason to be cautious. A broken checkout costs money directly, and that caution reliably turns into six-month-old plugins.

The resolution is a staging copy, not deferral. Test updates there, apply them promptly, and keep automatic updates on for everything that is not business-critical. A store running old plugins is in far more danger than one that occasionally needs a layout fixed. Enabling automatic updates goes into splitting the two.

HTTPS everywhere, not just checkout

Partial HTTPS is worse than it looks. The session cookie identifying a logged-in customer or administrator is sent with every request, including the plain HTTP ones, where anyone on the network path can read it.

Securing checkout while serving product pages over HTTP leaks the session on every product page. Redirect the whole site. Forcing HTTPS explains it, and Ahosting includes free SSL so there is no cost argument.

Do not handle card details yourself

Use a payment gateway that takes card details on its own infrastructure or in an embedded field it controls. Your server then never touches a card number.

The alternative (card data passing through your site) puts you inside a compliance scope most small stores are not equipped to satisfy, and it converts any compromise into a considerably more serious event.

This is one of the few decisions where the easy option is also the correct one.

Administrator accounts

Two-factor authentication on every account that can install plugins or view orders. A stolen password then achieves nothing on its own.

Give staff the lowest role that lets them work: someone processing orders does not need to install plugins. And remove accounts when people leave, which is the step that gets skipped for years.

Limit login attempts so automated guessing is too slow to be worth an attacker's time.

What to watch for

A store gives you signals an ordinary site does not.

Unexpected administrator accounts. A common first step after a compromise.

Order patterns that look like card testing; many small orders in quick succession with different cards, most failing. Your store is being used to validate stolen numbers, and the processor will notice before you do.

Files changing outside an update. File change detection catches this and it is one of the few ways to notice a compromise you were not looking for.

Backups you have restored

Every layer above tries to prevent a compromise. A backup is what remains when one did not work, and on a store it needs to be frequent. A day-old backup means a day of lost orders.

Keep copies off the server, keep enough history to reach back past a compromise discovered late, and restore one once to confirm it works. Managing WordPress backups deals with the discipline.

Have a plan for the breach

Worth writing down before you need it: how you would take the store offline, who you would tell, and what your obligations are for notifying customers whose data was exposed.

Those obligations are real and have deadlines. Working them out during an incident is considerably worse than having read them once.

Find out what is actually installed

A shop accumulates code over years, and the inventory is the first honest look at the exposure.

wp plugin list --fields=name,version,status,update
wp plugin list --status=inactive --field=name
wp theme list --fields=name,version,status

Inactive plugins are still files on the server and can still be reached directly. Deactivating something is not removing it, and a vulnerable file does not need the plugin to be active to be requested.

Remove what is not in use rather than leaving it deactivated. The list should be short enough that you can say what each entry does and why it is there.

Watch the accounts, not only the code

Most compromises of a shop arrive through a login rather than through a flaw, and the record of that is available.

wp user list --role=administrator --fields=ID,user_login,user_email,user_registered
wp user list --field=user_login --role=shop_manager
awk '$7 ~ /wp-login/ && $9 == 200 {print $1}' ~/logs/example.com | sort | uniq -c | sort -rn | head

An administrator account created on a date nobody recognises is the finding. So is a successful login from an address that appears once and never again.

Reduce the number of accounts with full privileges to the number of people who genuinely need it, which on most shops is one or two rather than the six that have accumulated.

Know what a breach would actually expose

Planning the response requires knowing what is held, and that is a question most shop owners have not answered precisely.

wp db query "SELECT COUNT(*) FROM wp_users;"
wp db query "SHOW COLUMNS FROM wp_postmeta LIKE '%billing%';" 2>/dev/null
wp db query "SELECT COUNT(*) FROM wp_woocommerce_order_items;" 2>/dev/null

Names, addresses, telephone numbers and order histories are all in the database. Card details should not be, and confirming that rather than assuming it is worth doing once.

Where a plugin stores anything beyond what the payment provider handles, that is a decision somebody made and it changes what a breach means. Configuring payment gateways covers keeping that data elsewhere.

Decide who is responsible before something happens

Security on a shop fails most often through absence rather than through a technical flaw, and the absence is of a person. Name who applies updates, who reads the alerts, who is called at the weekend and who talks to customers if data is exposed. Where the answer to any of those is nobody, that is the finding, and it is more important than any individual setting. Writing it down converts a shared assumption into an arrangement somebody can be held to.