Image Security with Cloudinary

By  on  

When developers think about security within their web apps, seldom does image security top the list; not because securing media isn't important, of course, but because media security isn't always easy.  Some will even tell you that media security isn't important, but if you want to keep media owner information secure, want to cut down on bandwidth and hotlinking, or simply want credit for the media, it's incredibly important that you take steps to guard media s best you can.

Cloudinary recognizes that their users' media is important and provides various features to help developers keep images secure, watermarked, and used only as intended.  Let's have a look!

Basic Watermarking

The watermarking technique has been used by photographers and stock photo sites since the early days of the internet. There are a few different strategies for watermarking, all of which Cloudinary allows you to control:

  • Watermark in a certain spot over an image
  • Repeated 50% opacity watermark throughout the image
  • Text as watermark

Implementing each of these watermarking techniques is easy with Cloudinary:

Watermark On Image

https://.../l_logo,g_south_east,w_100,x_20,y_20,o_60/v1486595264/ringo.jpg

Repeated Watermark

https://.../l_logo,w_100,x_20,y_20,o_20,fl_relative.tiled/v1486595264/ringo.jpg

Text Watermark

https://.../l_logo,w_100,x_20,y_20,o_20,fl_relative.tiled/v1486595264/ringo.jpg

Invisible Watermarking

My friends at Cloudinary showed me an amazing technique for "invisible watermarking" using low opacity in the blue channel which is hard for the human eye to see.  Consider the following image:

<img src="https://res.cloudinary.com/demo-robert/image/upload/l_text:arial_30_bold_stroke:David%20Walsh%20Blog,bo_15px_solid_rgb:000000,a_45,e_screen,o_7,co_rgb:0000FF,fl_tiled/q_90/234_72_z_qpwsct.jpg">

You probably can't tell but the image above is watermarked.  If you upload this image to your Cloudinary account and applied a blue channel transformation, you would see your watermark as clear as day:

<img src="https://res.cloudinary.com/demo-robert/image/fetch/e_green:-100/e_red:-100/e_auto_contrast/https://res.cloudinary.com/demo-robert/image/upload/l_text:arial_30_bold_stroke:David%20Walsh%20Blog,bo_15px_solid_rgb:000000,a_45,e_screen,o_7,co_rgb:0000FF,fl_tiled/q_90/234_72_z_qpwsct.jpg">

This effect is amazing and a great way to tag your images whilst not adding distracting traditional watermarks. If someone takes a screenshot of your image, the blue technique will still see watermark text!

Token or Cookie-Based Authentication for Transformations

Securing content to a viewer by IP or token is common-place, oftentimes to provide previews of content before it goes live.  Whatever your reason for securing content by ID or token, Cloudinary allows you to limit image render by IP incredibly easily:

// Only allow users at 192.168.0.1 to see the image
cloudinary.image("contract.png", { 
  type: "authenticated",  
  auth_token: {
    key: "_key_", ip: "192.168.0.1"
  }, 
  sign_url: true });

If you're prefer not to isolate by IP (which is incredibly strict), you can instead limit image render to cookie! To secure image to cookie value, you create a CNAME which points Cloudinary, whereby Cloudinary can ensure a cookie is set on your main domain and then serve the image accordingly. Now *that's secure!

Signed URLS

One advantage to using Cloudinary is the ability to create images on the fly by simply modifying the image URL, but there may be times that you want signed image URLs so that additional transformations cannot be added to the image by another party; in that case, you'd use the sign_url parameter to sign an image:

cloudinary.image("yellow_tulip.jpg", {
  sign_url: true,
  width: 300,
  height: 200,
  crop: 'crop',
  gravity: 'center'
});

Which renders an image with a signature:

<img src="https://.../image/upload/s--o1_ZfmFP--/c_crop,g_center,h_200,w_300/yellow_tulip.jpg">

Trying to access a different transformation or including an invalid signature will result in a 401 error response!

Private Images

Cloudinary allows you to set a private parameter when you upload an image:

cloudinary.uploader.upload(
  'sheep.jpg', 
  result => {}, 
  {
    public_id: 'sheep', 
    type: 'private'
  });

Once the image is uploaded, if a user tries to hit a private image directly, it will not display!  If you want to allow the image to only displayed in certain dimensions and other transformations, you'll need to use Cloudinary's management console to create rules for strict transformations of your image:

With your strict image rules in place, you can display just the transformed image with the following URL:

<img src="https://res.cloudinary.com/private-demo/image/private/w_300,h_200,c_fill,r_20/sheep.jpg" alt=""gt;

EXIF Data Removal

Most people don't realize that when you take a photo with any modern photo or camera, the image file contains scores of metadata include where the image was taken, what device the image was taken with, much more.  I recently wrote about getting and removing EXIF data using exiftool, but if you're using a third party to manage or upload user media, you'll want to ensure they remove EXIF data, which Cloudinary does by default for new transformations.

If you'd like to keep metadata, add the keep_iptc flag to the image:

cloudinary.image('sample.jpg', {
  width: 300, 
  flags: 'keep_iptc', // keep EXIF data
  crop: 'scale'
});

I love that EXIF data is saved on raw image uploads but removed on transformed images -- it's the best way to keep your original image while keeping the uploader safe!

Referral-Based Whitelisting

Cloudinary allows you to provide a whitelist for image referrers:

This feature is available for our Premium plans only. In addition, a custom CNAME must be set-up for your account for this to work. You need to let us know the domains you want to be whitelisted for your account and following a short manual configuration on our side, any request for access to an image that does not come from a domain on the whitelist will be denied. Likewise any request for access to an image that comes from a domain on the blacklist will be denied.

If you really want to lock down your images, so as not to incur bandwidth fees, this seems like a really good idea.

There's a common misconception that there's nothing you can do to protect your media and intellectual property, especially when you play it on an external service. In reality, there's a lot you can do to protect media and Cloudinary offers numerous ways to do so. I can't speak highly enough of Cloudinary -- they provide every effect, API, and security set you could ever want!

Recent Features

  • By
    fetch API

    One of the worst kept secrets about AJAX on the web is that the underlying API for it, XMLHttpRequest, wasn't really made for what we've been using it for.  We've done well to create elegant APIs around XHR but we know we can do better.  Our effort to...

  • By
    Responsive and Infinitely Scalable JS Animations

    Back in late 2012 it was not easy to find open source projects using requestAnimationFrame() - this is the hook that allows Javascript code to synchronize with a web browser's native paint loop. Animations using this method can run at 60 fps and deliver fantastic...

Incredible Demos

Discussion

    Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!