LeagueSpot's Identity Verification System: How We Securely Handle Sensitive Information
Running remote competitive events, especially those open to the public, introduces a challenging problem for safety-focused tournament organizers: how do I know that these competitors are who they say they are? This is especially important in communities focused on youth and/or underrepresented competitors where trust is even more critical.
To solve this problem, LeagueSpot has implemented an identity verification flow that requires that any competitors new to a community must submit a verification image that meets the community’s criteria. For example, a Reddit-style selfie or a photo of their driver’s license or state ID. Due to the sensitive nature of these images, LeagueSpot approached the solution from a security-first paradigm to live up to the trust that we have built as the guardians of our users’ data.
The purpose of this content is primarily to share our commitment to securing our communities’ data, but also to serve as a resource to other software platforms with similar security needs - we strongly urge that you borrow these strategies and policies for your own implementations.
Strategies to secure sensitive data
Any good data security plan consists of multiple redundant strategies that seek to primarily restrict access to confidential resources, but secondly to isolate the impact of a single incident to as few records as possible. With this in mind, we implemented the following overlapping policies to ensure that these sensitive images are not accessed by unauthorized users.
Make the cloud storage container private and generate a unique, read-only and short-lived access token per image load
Our application leverages the approvers’ LeagueSpot authorization credentials and resulting privileges to generate access tokens that are required to load every image. These tokens only work on a single image, so gaining access to one cannot be applied to another. Additionally, these tokens only need to live long enough for the image to be viewed exactly once on request from the browser, so even if the image URL were to be compromised and shared, accessing that URL beyond 30 seconds after the initial load will cause the load to fail.
Introduce randomness to the image URL to avoid predictable discovery
When image URLs follow a pattern and become predictable - say, including only a user’s ID - then a user who discovers one image can extrapolate that pattern to systematically discover other images from the same community.
To avoid this type of attack, we add a nondeterministic, random fragment into image URLs such that having access to one image does not support a pattern that leads to discovering others.
Never show all images in a list to avoid accessing more images than absolutely necessary
Every time an approver loads an image in a browser, especially on a private device in a public space or with a shared device, it increases the chance that an unauthorized user can view sensitive content such as the photo, name and address on a driver’s license.
To reduce this risk, images are only loaded when the approver explicitly views an item, which significantly limits data exposure.
Instruct the browser to never locally store these sensitive images
When a web browser downloads images, it typically stores a copy locally so that every time the user loads the page, it doesn’t have to re-download that image. While this methodology does improve page load performance, it also stores that image on the computer - which is unacceptable for such secure data.
To resolve this issue, we made sure these images are delivered to the browser with a “no-store” cache control header, which instructs the browser to never store these images locally. These images will need to be downloaded on every request, but they also will never sit on a hard drive - which is especially important on shared devices.
Add a storage policy that automatically deletes images after 60 days to avoid data retention issues
Any service that obtains and stores data will grow over time as users submit new data. As the data volume grows, the cost of unauthorized access grows as well. One of the most effective ways to mitigate this risk is to reduce the amount of sensitive data retained within environments. Adding an expiration policy to these images ensures that, should they be compromised, the attacker will only have access to the last 60 days of data as opposed to the entire history of all submissions.
Limit developer cloud storage access to accounts based on principle of least privilege and protected by MFA
As is true with any software, engineering team members are vectors for attack since they can be socially engineered to gain access to protected systems. LeagueSpot limits our engineers’ access based on least privilege - meaning they only have access to resources that are required to do their jobs. And we have a strict access policy that requires that all access is protected by multi-factor authentication, further reducing the risk that even in a social engineering attack, access is still not granted without access to a second form of authentication.
We take our role as the guardians of your data seriously. With the increasing number of data breaches and cyber attacks, it is important for individuals and organizations to take proactive steps to secure their data. By following best practices like those listed above, we can work together to protect sensitive data from potential threats.
If you have any questions or want to talk about securing your data, please reach out at email@example.com.