Azure & Cloud Architecture
Using Azure Blob Storage Securely from .NET
Blob security depends on identity, network path, delegation scope and data lifecycle together. A private container is only one control; application code can still issue excessive SAS tokens or cross tenant boundaries.

Prefer identity over account keys
Use managed identity and Microsoft Entra authorisation for application access where possible. Assign the narrowest data-plane role at the smallest practical scope. Storage account keys grant broad power, are difficult to attribute and make rotation an application event.
Control-plane access to configure an account is distinct from data-plane access to blobs. A contributor role does not automatically mean the principal should read customer files.
Access patterns
| Pattern | Use | Risk |
|---|---|---|
| Managed identity SDK access | Trusted service-to-storage calls | Over-broad RBAC scope |
| User delegation SAS | Short direct client transfer | Bearer URL usable until expiry |
| Application proxy | Inline policy, transformation or audit | App bandwidth and connection cost |
| Private endpoint | Private network access | DNS and egress-path complexity |

SAS is delegated bearer access
Prefer a user delegation SAS signed through Entra credentials over account-key SAS when SAS is required. Limit resource, permissions, protocol and expiry. Set start time only when needed because clock skew can make a token appear not yet valid.
Anyone possessing the URL can use it until expiry. Do not log query strings, place SAS values in analytics or use long lifetimes for convenience. Revocation is difficult; stored access policies help some SAS forms, while key rotation is a disruptive last resort.
Blob names are not authorisation
Opaque GUID paths prevent guessing but do not prove access. Resolve tenant and resource ownership in authoritative application data, then construct the blob reference. Never accept an arbitrary container/blob pair from a caller and pass it to a privileged storage client.
Normalise naming rules and bound length. Metadata and tags are useful indexes but are not a substitute for authoritative relational ownership where consistency matters.
Uploads are an untrusted-content workflow
Limit size before and during transfer, validate expected media and scan where risk requires. Extensions and client content types are not proof. Upload to a quarantine path, record state, scan asynchronously and only then publish or expose the blob.
Use conditional requests or unique names to prevent accidental overwrite. For direct client uploads, issue write-only scope to one target and require the application to verify completion before marking the business record ready.
Downloads need content controls
Set safe Content-Type and Content-Disposition; sanitise filenames. Active HTML/SVG content served from an application-trusted domain can execute in a browser context. Isolate user content on a separate domain and apply conservative headers.
Stream large files or redirect to short-lived SAS delivery. Avoid buffering whole blobs in application memory. Range support requires a stable representation and validators.
Private endpoints change DNS
A private endpoint is effective only when clients resolve the storage hostname to the private address and public access is restricted according to policy. Test application, build agent, Function and operator paths. Split-horizon DNS mistakes often appear as intermittent timeouts rather than authorization errors.
Private networking does not replace identity. A workload on the network should still receive only its required data-plane permissions.
Encryption needs a threat model
Azure Storage encrypts data at rest. Customer-managed keys add control and operational responsibility: key availability, permission, rotation and recovery can affect every blob. Application-level envelope encryption is justified when storage administrators or platform access must not reveal plaintext, but it complicates search, range reads and key recovery.
Never invent cryptography or store the data-encryption key beside ciphertext without a protected wrapping design.
Lifecycle is part of security
Configure retention, tiering and deletion from legal and business requirements. Soft delete and versioning improve recovery but retain data longer and increase cost. Legal hold and immutability deliberately prevent deletion; test operational consequences before enabling them.
Orphan cleanup needs reconciliation between business records and blobs. Event-driven deletion alone can be lost; periodic inventory should find incomplete uploads and abandoned versions safely.
Production checklist
- Use managed identity and least-privilege data roles.
- Disable or restrict Shared Key where compatible.
- Use short, narrow user delegation SAS tokens.
- Keep SAS query strings out of logs.
- Authorise tenant/resource ownership before storage access.
- Quarantine and scan untrusted uploads.
- Stream large transfers and isolate active content.
- Test private DNS and public-access restrictions.
- Align lifecycle, soft delete and versions with retention policy.
- Audit access without logging sensitive blob names unnecessarily.
Account keys collapse the security boundary
An account key grants broad authority and is difficult to attribute to one workload. Prefer managed identity with Azure RBAC for server applications. This removes a stored credential and makes access changes visible through identity policy.
Grant roles at the narrowest practical scope and separate data operations from management operations. A deployment pipeline that creates infrastructure does not automatically need to read customer blobs; a runtime uploader does not need to alter networking.
If legacy account keys remain, inventory every copy, rotate with overlap and monitor shared-key use. Disabling shared-key authorisation can be a strong control once every legitimate path uses identity or delegated access.
SAS design starts with who may do what, until when
A SAS is a bearer credential embedded in a URI. Anyone who obtains it can exercise its permissions until expiry or revocation. Keep scope, permissions and lifetime narrow, use HTTPS and never place SAS URLs in analytics or ordinary logs.
User-delegation SAS is generally preferable when Entra identity can issue it because it avoids signing with the account key. Stored access policies can aid revocation for service SAS in supported scenarios, but operational limits and propagation still need understanding.
Authorise the user before minting a SAS and generate the resource path server-side. A signed URL should not turn an untrusted blob name into access to another tenant.
Upload completion is not content acceptance
Direct-to-blob upload keeps large bodies away from the application, but the uploaded object is untrusted. Place it in a quarantine location with no public serving path, validate expected size and type, scan content and then promote or mark it accepted.
File extension and client MIME type are claims. Inspect signatures where practical and set server-controlled content metadata. Archives need limits on extracted count and size to resist decompression bombs and path traversal.
Use unique server-generated names and keep the original display name as sanitised metadata. Never concatenate a user filename into a filesystem or blob path and assume URL encoding creates authorisation.
Downloads can turn storage into an attack delivery service
Set Content-Type, Content-Disposition, nosniff and cache policy according to trusted server metadata. Serving active HTML or SVG inline from an application origin can execute content in a user's security context.
Consider a separate download origin for untrusted content and force attachment where business needs allow. Scan status must be checked at download time, not only reflected in a UI badge.
Range requests improve large-file experience but complicate auditing and proxy caching. Ensure authorisation applies to every request and do not log full signed URLs.
Concurrency and immutability require explicit semantics
ETags enable conditional writes and deletes so two processes do not silently overwrite each other. Use If-Match when updating a known version and handle precondition failure as a business conflict.
Immutable storage can protect regulated records from alteration for a retention period, but incorrect retention locks can make legal deletion or correction impossible. Governance and testing matter as much as enabling the feature.
Blob versioning and soft delete aid recovery but increase retained data and cost. They are not substitutes for an independent recovery strategy, and old sensitive versions remain part of the data lifecycle.
Tenant isolation extends beyond container names
Dedicated accounts offer stronger key, network, quota and recovery isolation. Per-tenant containers provide organisational and delegated-access boundaries at lower operational cost. Shared paths provide density but depend heavily on flawless application authorisation.
Choose according to customer count, regulatory isolation, noisy-neighbour risk and fleet automation. Include tenant scope in indexes, event messages, lifecycle rules and diagnostic queries. A correct primary path can still leak through generated thumbnails or exports.
Restoring one tenant from a shared account may be substantially harder than restoring the account. Recovery granularity should influence the isolation choice before an incident.
Lifecycle policy is part of the domain
Retention differs between temporary uploads, completed evidence, generated reports and failed quarantined files. Use metadata or tags controlled by the service to drive transitions and deletion; do not infer policy from user filenames.
Lifecycle actions are asynchronous. Applications should not promise immediate deletion merely because a rule exists. Define what happens in versions, snapshots, replication and backups, and verify expiry with monitoring.
Archive tiers reduce cost but introduce retrieval delay and charges. A business recovery objective may make cold storage inappropriate even when monthly storage cost looks attractive.
Observe operations without exposing objects
Monitor authorisation failures, unexpected shared-key use, public-access changes, unusual egress, scan backlog and lifecycle errors. Record tenant, operation and safe object identity without logging SAS tokens or sensitive names.
Private endpoints change DNS and routing; test applications, build agents and recovery tooling from their actual networks. A firewall rule that protects production but prevents incident restoration is incomplete.
Secure Blob Storage is a lifecycle: authorised creation, quarantined inspection, controlled serving, version-aware change and provable deletion. Encryption at rest is only one platform control inside it.
Related C3 Software guides
Frequently asked questions
Should .NET applications use storage account keys?
Prefer managed identity and Entra RBAC. Account keys are broad shared credentials.
Which SAS type is preferred?
Use a short-lived user delegation SAS where supported and scope it to the exact operation.
Does a private endpoint make blobs secure?
It restricts network reachability; identity, application authorisation and data lifecycle controls remain necessary.
Should downloads pass through ASP.NET Core?
Only when proxying adds policy, transformation, audit or isolation value; otherwise direct delegated transfer can scale better.
Secure the complete blob lifecycle
C3 Software Limited has built and supported business software in the UK since 2001. For storage security reviews, talk to C3 Software.