Note: This is an exercise in understanding AWS Amplify API KEY Auth and Storage configuration in order promote more secure application development. Please use this information to better protect and monitor your applications.
How to use someone else's AWS account to create a platform to share and store an unlimited amount of data.
AWS Amplify is described as a platform for building scalable and secure mobile and web applications, allowing developers to design and deploy a backend in just 30 minutes. For this tutorial we will use the scalable part of the platform. What is important is that out of the box, Amplify doesnn't help much with business logic. In 30 minutes a CRUD API can be setup, and can be connected with S3 for storage. Of course, an open CRUD API without any type of validation isn't an app, it's an invitation for abuse. Let's use it to create our own app, Sharebox. Sharebox has a simple goal, allow any user to upload an unlimited amount of files, and allow anyone else to download these files, all at zero cost (to us).
The key is to find an Amplify application with S3 storage configured and allows unauthenticated requests. When an Amplify app uses API keys
to grant access to cloud resources, it uses Amazon Cognito to create temporary AWS credentials to access resources. In order for us to use another app's database the only thing we need to do is find the Cognito endpoint used to fetch these credentials. Luckily a simple peek at the network tab while interacting with an app is sufficient.
Once we have the credentials, we can interact with AppSync to manage the database, and we can use Amazon S3 to store and read large file object.
Finding one of these projects is probably the hardest part, so watch on popular websites for posts about Amplify and how quickly a backend was stood up, and especially where the app appears to support image uploads.
Let's imagine we found a CV review service, and that the developer lives in a region where attaching a photo to a CV is common practice. The schema.graphql file may look like the below, which you could also determine by looking at the AppSync API schema introspection endpoint
# Other types elided...
type Candidate @model {
id: ID!
cvCandidatesId: ID
name: String! # The CV user's name
userScore: Int! #0-100
image: String # Photo to attach to CV
}
type CV @model {
id: ID!
cvData: String!
candidate: Candidate @connection
}
The API object we will (ab)use in this case is the Candidate model, since it appears we can insert data that will be well hidden, as the frontend of the web app never queries this data directly, but instead works through the CV model. With this model we can build our own API. For our Sharebox app we need to use the 'id', 'name', 'image', and 'userScore' field. For our app we will re-purpose 'image' to be the S3 bucket path for the data we store, 'id' and 'name' are self-explanatory, and we will set 'userScore' to -100 so we can filter in the database to only return our Sharebox related data.
Now we can utilise the GraphQL CRUD API to insert our first item's metadata:
mutation {
createCandidate(input: {
name: "a very large video",
userScore: -100,
image: "bucketName/public/Sharebox/myBigVideo1.mp4"
}) {
id
}
}
And read it out again:
query {
listCandidates(limit: 999, filter: {userScore: {lt: -99 }}) {
name
image
}
}
To run these graphql queries, use aws4fetch to make the request, and pass in access key, secret key, and session token fetched from Cognito.
Now the only part remaining is to insert the video into S3 and read it out.
Inserting data is equally easy, using the same aws4fetch library we can create a signed request to utilise the bucket, and then upload the file with a normal fetch request. A nice trick at this point is to set the 'x-amz-acl' request header to 'public-read'. This way we don't need to construct a signed URL to retrieve the data. Note that the bucket path must begin with 'public/', as by default this is the prefix Amplify sets aside for non-authenticated users.
Reading out the data at this point is an easy fetch.
To build out a frontend, we can use Cognito to get credentials, list our files from the Candidate model, offer links to download any file, and have a file upload utility which gets a presigned url and allows an upload. When the upload finishes we can insert a not database item in the Candidate model and give the file a custom name to display in our UI.
There are some downsides. First, any user can delete an item in S3 and our data could become inconsistent. Second, our app only works so long as someone provides a free open bucket and API. And third, anyone with billing notifications on will soon get an alert and shut this app down.
Top comments (0)