Securing document objects with AWS CloudFront Signed URLs

Security Mar 7, 2022

Millions of users use Halodoc Services and protecting their information is the one of the most important responsibilities we have at Halodoc. Multiple documents are shared across different platform such as Digital Prescriptions, Invoices etc. which potentially contains sensitive users information. But, were these documents shared securely with the users?

Documents served to the users were static URLs and secured using AWS CloudFront over HTTPS. However, the URLs are publicly accessible and user can access the same URL anytime without any expiration. For example, let's consider the use-case, the doctor shared the digital prescription URL with user. As the URL is static and will never expire, a document can be accessed anytime in the future, even beyond the expiration period of the prescription. Such breaches are avoidable by configuring AWS CloudFront to deliver these static URLs as SignedURLs instead.

So what are Signed URLs anyway?

A signed URL is an URL that you can provide to your user to grant temporary access to a specific S3 object. A signed URL includes additional information, for example, expiration date and time, that gives you more control over access to your content. The URL needs to have some specific parameters like
Expires :  The time that you want the URL to stop allowing access to the file.
Signature :  The hashed and signed version of the policy statement.
Key-Pair-Id :  Public key ID for the CloudFront public key whose corresponding private key you're using to generate the signature

Need for the securing documents using signed URL

  • We have a use case where Hospital Users need to verify patient's information through any one of the forms of IDs prescribed by the Indonesian Govt. This ID is uploaded by patients for Hospital Appointments. As this ID is a personal identification document of the User, we have configured them to be accessible via a signed URL with a certain expiry time.
  • Similarly, all the documents which are shared across Halodoc services, like doctor notes, digital prescriptions, lab reports, invoices etc as signed protected with a certain expiry time.

So how does the signed URL works?

  • Whenever the user requests a file for which we have to generate a signed URL, the application verifies that the user is entitled to access the file by providing the permissions to AWS CloudFront and it verifies using Signature and provided Key-Pair.
  • Once the request is validated, a signed URL allows the user to download or stream the content. If the users hits the URL on the browser, CloudFront uses the public key to validate the signature and confirm that the URL hasn't been tampered with. If the signature is invalid, the request is rejected.
  • If the signature is valid, CloudFront looks at the policy statement in the URL with the specified end-date time. If the request meets the requirements in the policy statement, CloudFront does the standard operations: determines whether the file is already in the edge cache, forwards the request to the origin if necessary, and returns the file to the user.
  • The signed URL is tamper-resistant -- the expiration time is embedded in the URL, but attempting to tweak it after signing will invalidate the signing and make it useless.

Implementation

AWS CloudFront java SDK provides support to generate signed URL for S3 objects.

A function that generates a signed URL.

Generating Signed URL using Canned Policy

How secure signed URLs are in terms of Security?

AWS CloudFront does a great job to share the s3 objects with low latency, high transfer speeds, and over HTTPS. But, there is more to it in terms of security.

  • You can specify the date and time that users can begin to access the content.
  • You can specify the date and time that users can no longer access the content.
  • You can specify the IP address or range of IP addresses of the users who can access the content.

How does a signed URL look like?

The URL looks a bit wide as it contains the encoded security credentials and also Expires param specifies how long the URL will live.

document_url is the signed url

What if trying to access the signed URL after expiry?

Access Denied!

Limitations

However, generating signed URLs using canned policy helped us in securing documents but there are few limitations :

  • The content can be streamed/downloaded multiple times until the URL expires, hence need to choose the expiration time wisely.
  • Canned policies, then, are (at least to some extent) more "lightweight" -- shorter URLs mean fewer bytes included in the request, and somewhat less processing needed to use them, but they have less flexibility than custom policies.
  • The signed URLs do not support limiting the file size.
  • The signed URLs expiry date can be set a maximum of 7 days.

Why choose CloudFront signed urls over S3 Presigned Url?

S3 presigned urls are way more flexible as it provides selection of content type, Content-MD5 header, zeroByteContent. However using Cloudfront signed url will have reduced latency as it supports  edge locations, HTTP/2 support for request multiplexing, and a single domain, which means no CORS problems and a simplified CSP.

How to revoke a signed URL?

It can be revoked directly from cloudfront by distrusting the key pair  permissions, hence those key pair can never be used to generate the signed URLs.

Summary

In this post, we discussed how signed URLs are helpful in terms of security and the use of AWS CloudFront SDK to access your s3 objects as signed URLs using canned policy. Further steps would include making documents more secured using presigned URLs and custom policies for signed URLs.

Join us

We are always looking out for top engineering talent across all roles for our tech team. If challenging problems that drive big impact enthral you, do reach out to us at careers.india@halodoc.com

About Halodoc

Halodoc is the number 1 all around Healthcare application in Indonesia. Our mission is to simplify and bring quality healthcare across Indonesia, from Sabang to Merauke. We connect 20,000+ doctors with patients in need through our Tele-consultation service. We partner with 3500+ pharmacies in 100+ cities to bring medicine to your doorstep. We've also partnered with Indonesia's largest lab provider to provide lab home services, and to top it off we have recently launched a premium appointment service that partners with 500+ hospitals that allow patients to book a doctor appointment inside our application. We are extremely fortunate to be trusted by our investors, such as the Bill & Melinda Gates Foundation, Singtel, UOB Ventures, Allianz, GoJek and many more. We recently closed our Series B round and In total have raised USD$100million for our mission. Our team works tirelessly to make sure that we create the best healthcare solution personalised for all of our patient's needs, and are continuously on a path to simplify healthcare for Indonesia.

References

Gaurav Sardana

Keep doing things to become the best version of myself.