How to display sensitive images to authorized users while preventing browser caching and protecting files at rest — using System.Drawing.Image, MemoryStream, and Base64 encoding.
A common challenge in web applications: you need to display an image to the user, but the image is sensitive — it shouldn't be cached by the browser, shouldn't be accessible anonymously, and should be protected at rest on the server. Serving it directly via a static URL solves none of those problems.
The solution is to never serve the file directly. Instead, serve it as a Base64-encoded data URI generated server-side on demand, returned through an authenticated web service call. The browser displays the image without ever receiving a cacheable file reference.
Access the protected file on the server and load it into a System.Drawing.Image object. This gives you a .NET representation of the image that you control entirely — the file itself never goes near the HTTP response.
Use a MemoryStream inside a using statement to convert the image into a byte array. Save the Drawing.Image in its RawFormat attribute, then call ToArray() on the stream to extract the bytes.
using (MemoryStream ms = new MemoryStream())
{
image.Save(ms, image.RawFormat);
byte[] imageBytes = ms.ToArray();
}
Convert the byte array to a Base64 string and format it as a data URI. Return this string from your web service. On the client side, assign it directly to an image element's src attribute.
string base64 = Convert.ToBase64String(imageBytes);
string dataUri = string.Format("data:image/jpeg;base64,{0}", base64);
// Called asynchronously from your client script
imgElement.src = dataUri;
Base64 encoding increases the size of the data by approximately 33%. For large images, this means significantly larger payloads in the HTTP response. This can cause performance issues if executed at runtime without caching, or if the Base64 string is stored in ViewState — which can result in bloated page sizes and slow load times.
For most use cases involving document thumbnails, ID photos, or certification images, the size trade-off is acceptable. For large images or high-volume requests, consider caching the Base64 string server-side with an appropriate expiry tied to the user's session.