Security . v5.3

Building blocks for secure upload workflows.

AjaxUploader is not a compliance product - it is a set of hardening primitives you compose into a secure system. Encrypt files in the browser, keep cloud credentials and OAuth tokens server-side, scan for malware, and validate real content type, all without rewriting your .aspx pages.

Encryption at rest (client-side)

Files are encrypted in the browser with AES-GCM-256 via the Web Crypto API before a single byte leaves the page. The key is derived with PBKDF2 over a configurable iteration count. Encryption metadata travels in X-Mu-Encryption-* headers, and a decryptFile helper reverses the process. Useful when you do not trust the transport or the storage tier.

Companion broker - credentials never reach the browser

The self-hosted Node OAuth broker keeps provider client secrets and access tokens server-side. The browser holds only a signed, HttpOnly session cookie. The OAuth state value is HMAC-signed for CSRF protection. Contrast this with the in-browser pickers (implicit OAuth, token sitting in client JS) - the broker is the hardened option.

Server-side signers - no cloud keys in the browser

Direct-to-S3, Azure, and GCS uploads are signed server-side through reflective IS3Signer / IAzureSigner / IGcsSigner DI. The browser receives a short-lived signed URL - never your cloud account keys.

Those presign routes are privileged: anyone who can call them can obtain credentials to write into your bucket. Because the handler is registered application-wide, a <location> rule on ajaxupload.axd would also gate ordinary uploads - so gate signing specifically with AjaxUploader.Security.SigningAuthorization.Handler, set once in Application_Start. Denials answer 403, and the check runs before the "signer not configured" branch so a rejected caller cannot discover which providers you have wired up.

Authorizing the endpoint is only half of it. The presign flow spans several requests and only create chooses the object key - every later call re-sends the key and upload id from the client. Set AjaxUploader.RequireSignedCloudSessions (or the <appSettings> key of the same name) to true and the server issues a signed session token on create, requires it afterwards, and uses the key it holds instead of whatever the client sends. Tokens are protected with the ASP.NET machine key, so a web farm needs an explicitly configured, shared machine key - the same requirement as view state.

Virus scanning

A pluggable virusScan hook plus a dedicated /scan endpoint enable asynchronous post-upload scanning with quarantine semantics, so infected files never reach your trusted store.

Antiforgery / CSRF

Web Forms pages can opt in with EnableAntiforgery="true" on the upload control and bind ViewStateUserKey per session. The demo shows the exact markup and code-behind pattern for CSRF-resistant uploads.

Content validation

MIME magic-byte sniffing validates the real content type rather than trusting the extension, alongside extension, size, image-dimension, and aspect-ratio checks. All of it is enforceable server-side through the /validate endpoint.

Access control

Role-based upload gating runs through the upload security context, and a per-request headers callback lets you attach auth tokens to every transfer.

Upload storage hygiene

Keep temporary uploads under App_Data or private storage whenever possible. Public preview folders should be protected with no-index headers and short/no cache lifetimes so user files are not preserved by crawlers, browser caches, or shared proxies.

Transport hardening

HTTPS is required for the encryption, service-worker, and cross-tab features - Web Crypto and service workers need a secure context. Cross-tab coordination uses a lock so the same file is never double-uploaded.

Make it concrete

A couple of small examples.

Enable client-side encryption

uploader.configure({
  encryption: {
    enabled: true,
    passphrase: userSecret,
    pbkdf2Iterations: 250000
  }
});

Mount the Companion broker

const broker = require("companion-broker");
app.use("/companion", broker({
  providers: ["dropbox", "box", "drive", "onedrive"],
  sessionSecret: process.env.SESSION_SECRET
}));

What we do NOT claim

Honesty note.

AjaxUploader asserts no formal SOC 2, HIPAA, or ISO certification. The features above are building blocks you compose into a compliant system - they do not, on their own, make your application certified. License validation is performed server-side, and the obfuscated client bundle carries no secrets.