DEV Community

Cover image for Why Cloud Storage Needs More Than Just a Password
Fu'ad Husnan
Fu'ad Husnan

Posted on

Why Cloud Storage Needs More Than Just a Password

Cloud storage security still gets treated as a login problem, but the numbers say otherwise. Compromised identities now account for over 70% of cloud breaches, and human error drives 88% of all data breach incidents overall. A password, no matter how long or how often it's rotated, is a single point of failure sitting in front of an ever-expanding attack surface. If that one credential falls, everything behind it is exposed.

This gap matters more now than it did five years ago. Storage buckets, shared drives, and backup systems hold the operational core of most businesses: financial records, source code, customer data, internal communications. Attackers know this, and they've adjusted their methods accordingly. Credential theft, phishing, and session hijacking are cheaper and more reliable than exploiting a zero-day vulnerability, so that's where the effort goes.

The Password Was Never Meant to Carry This Much Weight

Passwords were designed for a simpler threat model: one person, one device, one login screen. They work reasonably well against random guessing. They work poorly against phishing kits that clone login pages in minutes, credential-stuffing bots that test billions of leaked username-password pairs, and infostealer malware that lifts saved credentials directly from a browser.

Once a password is compromised, an attacker doesn't need to "hack" anything else. They log in like a normal user. Most cloud storage platforms don't flag that kind of access as suspicious, because technically, it isn't — the correct credentials were used. This is why phishing remains the most prevalent breach vector, affecting roughly 73% of organizations, and why identity-based attacks are outpacing infrastructure exploits year over year.

The practical result is that a strong password policy alone gives a false sense of security. It raises the bar for guessing attacks while leaving the door open for theft, reuse, and social engineering — the methods attackers actually favor.

Multi-Factor Authentication Closes the Most Common Gap

Multi-factor authentication (MFA) doesn't eliminate credential theft, but it breaks the chain that turns stolen credentials into account access. A phished password is far less useful to an attacker if it can't be paired with a second verification step tied to a device or app the attacker doesn't control.

Setting this up doesn't require custom development in most cases — cloud storage providers expose it directly through their admin or account settings. For platforms that support programmatic enforcement, a basic policy check might look like this:

def enforce_mfa_policy(user_account):
    """
    Checks whether a user account meets minimum authentication
    requirements before granting storage access.
    """
    if not user_account.get("mfa_enabled"):
        raise PermissionError(
            f"Access denied: MFA not enabled for {user_account['email']}"
        )
    if user_account.get("mfa_method") not in ("app_totp", "hardware_key"):
        raise PermissionError(
            f"Access denied: unsupported MFA method for {user_account['email']}"
        )
    return True
Enter fullscreen mode Exit fullscreen mode

SMS-based codes are better than nothing, but they remain vulnerable to SIM-swapping attacks. App-based authenticators (TOTP) and hardware security keys are meaningfully stronger, and hardware keys in particular are close to phishing-proof, since the authentication is bound to the physical device and the specific domain being accessed.

Encryption Needs to Cover Data at Rest and in Transit — Consistently

Encryption is often assumed to be handled automatically by the cloud provider, and in many cases the baseline is. The gap shows up in the inconsistency: data might be encrypted in the primary storage environment but left unencrypted in a backup copy, a staging environment, or a third-party integration that syncs the same files elsewhere. Fragmented encryption coverage across multi-cloud and hybrid setups is a recurring theme in breach analysis, and it's rarely intentional — it's usually the result of teams adding new tools and storage locations faster than they update their encryption standards to match.

A basic encryption-at-rest example, using a standard library rather than a custom implementation, illustrates the principle:

from cryptography.fernet import Fernet

def encrypt_file(file_path, key):
    fernet = Fernet(key)
    with open(file_path, "rb") as file:
        original_data = file.read()

    encrypted_data = fernet.encrypt(original_data)

    with open(file_path + ".enc", "wb") as encrypted_file:
        encrypted_file.write(encrypted_data)

# Generate and store this key securely — never hardcode it
key = Fernet.generate_key()
encrypt_file("financial_report.csv", key)
Enter fullscreen mode Exit fullscreen mode

The code itself is straightforward. The harder part is governance: knowing where every copy of sensitive data lives, confirming encryption is applied consistently across all of them, and managing the encryption keys separately from the data they protect. A key stored next to the encrypted file defeats the purpose of encrypting it in the first place.

For data in transit, TLS should be non-negotiable for any connection to cloud storage — API calls, sync clients, and browser sessions alike. Most providers enforce this by default, but custom integrations and older client libraries sometimes fall back to unencrypted connections silently, which is worth auditing directly rather than assuming.

Access Controls Should Assume Compromise, Not Prevent It

Zero-trust architecture has moved from buzzword to default recommendation for a specific reason: it assumes that any credential, device, or session could already be compromised, and designs access accordingly. Instead of granting broad access once a user authenticates, zero-trust models re-verify continuously and limit what any single account can reach.

In practice, this means applying the principle of least privilege to cloud storage permissions. A marketing team member doesn't need write access to financial records. A read-only integration doesn't need delete permissions. Overly permissive IAM roles, particularly ones using wildcard permissions, remain one of the most common misconfigurations found in cloud security audits, and they're also one of the easiest to fix once identified.

# Overly permissive - avoid
policy_broad = {
    "Effect": "Allow",
    "Action": "s3:*",
    "Resource": "*"
}

# Scoped to what the role actually needs
policy_scoped = {
    "Effect": "Allow",
    "Action": ["s3:GetObject", "s3:ListBucket"],
    "Resource": "arn:aws:s3:::reports-bucket/*"
}
Enter fullscreen mode Exit fullscreen mode

The second policy limits blast radius. If the credentials tied to that role are ever compromised, the damage is contained to read access on one bucket, not full control over every storage resource in the account.

Monitoring and Audit Trails Turn Detection From Guesswork Into a Process

Even well-configured storage systems get breached. What separates a contained incident from a prolonged one is usually detection speed. Breaches spanning multiple cloud environments take an average of 276 days to identify and contain — a window long enough for attackers to move laterally, establish persistence, and extract data gradually enough to avoid triggering obvious alarms.

Audit logging closes part of that gap, but only if someone is actually reviewing the logs or alerting on anomalies within them. A missing or unreviewed audit trail is itself a contributing factor in a meaningful share of cloud security incidents. Basic anomaly detection doesn't require a dedicated security team to start:

def flag_unusual_access(access_log, baseline_hours=(6, 22)):
    """
    Flags storage access events outside typical business hours
    or from unrecognized locations.
    """
    flagged = []
    for event in access_log:
        hour = event["timestamp"].hour
        if hour < baseline_hours[0] or hour > baseline_hours[1]:
            flagged.append(event)
        if event.get("location") not in event.get("known_locations", []):
            flagged.append(event)
    return flagged
Enter fullscreen mode Exit fullscreen mode

This kind of check won't catch a sophisticated attacker who mimics normal behavior, but it catches a large share of automated and opportunistic access attempts, which still make up most incidents.

Backups Are a Target, Not Just a Safety Net

Backup systems used to be treated as the recovery plan for when something else went wrong. Attackers have caught up to that assumption, and now target cloud backups directly, since compromising a backup can undermine the recovery process itself — encrypting or deleting backups alongside primary data is a standard step in modern ransomware operations.

The fix isn't complicated in concept: backups need the same access controls, encryption, and monitoring as primary storage, plus one addition — immutability. A backup that can be modified or deleted by the same credentials that access daily operational data offers limited protection against a ransomware scenario. Write-once, read-many (WORM) storage configurations or versioned backups with delayed deletion policies address this directly, giving teams a recovery point that an attacker with valid credentials still can't erase.

Building a Realistic Security Layer

None of these measures function well in isolation. MFA without least-privilege access controls still leaves an over-permissioned account as a high-value target. Encryption without key management discipline just moves the vulnerability from the data to the key. Monitoring without a response process generates alerts nobody acts on.

The organizations with the strongest cloud storage security aren't necessarily the ones spending the most — they're the ones treating security as layered and ongoing rather than a checklist completed once at setup. Given that Gartner projects the vast majority of cloud security failures through 2026 will trace back to customer-side misconfiguration rather than provider failures, the responsibility mostly sits with the teams managing the account, not the infrastructure underneath it.

Start with what's already available: enable MFA across every account with storage access, audit current IAM permissions for anything broader than necessary, confirm encryption coverage extends to backups and integrations, and set up basic access monitoring if it isn't already running. None of these steps require a large budget. They require someone to actually go through the settings and fix what's been left open by default.

Top comments (0)