Suppose we have a web application for ebook shopping, users can only download books they have paid. And all those ebooks data(like epub data) are stored in S3, users will got a S3 download url when our app validated the user already bought one book.
I know S3 will generate a temporary and time-limited URLs to the user. But the problem is even the url is temporary and time-limited, what will happen if by any chance another user get the temporary url within the limited time?
Ok so one way seems to be letting the limited-time very short, like 10 seconds, but the potential risks still there.
I know this question is rigorous, how would you deal with it? Or forget it?
If the concern is that the buyer would distribute the URL, they could equally well distribute the file they've downloaded.
If the concern is that someone would get hold of the URL without the buyer's knowledge, then perhaps you could protect the download with a token that only the buyer would know (e.g. a password of some sort). This would make the URL unusable to anyone other than the buyer. The downside is that this will inconvenience the very people who've paid for your product.
Related
I'm building a social app, where users can choose what profile-picture they wish to display to others. I've currently implemented it as the following:
User sends the profile-picture file to my server
My server validates that the file size is not too large
My server uploads the file to a AWS S3 bucket, with a UUID prefix
The S3 bucket allows anyone in the world to download specific files, but not perform write/list operations
I store the profile-picture URL in my database, and send the link to other users as appropriate
The client for other users, upon encountering the profile-picture URL, will download the file and display it to the user
I'm now wondering if it's possible for a malicious user to upload a malware-file as his profile-picture, and take advantage of the fact that this malware will be stored in my S3 bucket, and downloaded onto many other users' phones.
How much of a concern is the above? Is there anything simple I can do to prevent such concerns? If not, what is the recommended way to store/distribute user-uploaded profile-pictures to others?
Edit: My server is in Java. Any Java specific library/tool advice will be appreciated as well
I'm developing a little multiplayer game app which requires users to have profiles and allows them to have profile pictures.
The game servers will be hosted on AWS EC2 and as database I plan to use DynamoDB with an additional Redis Cache. To store profile pictures I want to use S3.
The S3 server will be accessible directly from the app since I dont want to route all traffic over my game servers. Now I need to create a secure way to let users
up and download profile pictures. Every user is allowed to upload his profile picture but not every other user may download it.
Uploading should not be a problem since I can use my game servers to sign a link for uploading.
My concern is more about download. There is a "friend system" in the game
and only your friends may see your profile picture. Now I though of several ways to store this pictures securely to ensure the privacy of my users.
Do something with the url:
So the basic idea of this is that I will us a url that is hard to guess for an attacker.
http://s3-aws-region.amazonaws.com/profilpictures/[userid+random 128bit]
But I dont know if thats just enough. Maybe if there are more random bits?
Encrypt the picture:
Just encrypt the image. I would use AES with an 128bit key which is different for each picture and geneated on the users device. The server would store the key and give it only to the right persons.
As url I could use http://s3-aws-region.amazonaws.com/profilpictures/userid what makes the url calculatable. Downside: An attacker could calculate the url and get the encrypted picture. Is that a problem?
Do both:
The approach that guarantees most privacy for my users is just a combination of the both above. But is this enough? Or maybe even too much?
So what do you think about these approaches? Is there anything I didnt think of?
Don't overcomplicate things. Just send signed URLs to those users who should see the picture.
http://docs.aws.amazon.com/AmazonS3/latest/dev/ShareObjectPreSignedURL.html
I am trying to utilize S3 to let my clients download my software package. What I envision is creating a simple web app with authorization For example (download.mysoftware.com) Once the user is authenticated, they will be presented with a S3 url used to download the software. I will create user accounts based on my customers.
My concern is, what happens if the user copies the S3 URL link and then gives it to someone who isn't authenticated to download the software?
Is it possible to create an S3 policy that would prevent this and work for my usecase? I looked at allowing only specific IPs, however, I won't have a way to find out IP of my customers and wouldn't want to ask them first and then add it to the policy each time.
One way allowing specific IPs would work is if I allow downloads only from the IP that is linked to (download.mysoftware.com) but then the downloads will really be happened from my web application as opposed to from S3. Which seems like double effort.
When a user makes a request to download your application, generate a pre-signed URL for them with a short expiration. It only needs to be valid for as long as it takes them to start downloading your file, so even a few minutes of validity is likely to be plenty.
While it's technically possible for a user to share one of these URLs, they would have to convey the URL to someone else and get them to download it very quickly, which is probably sufficient to deter them from trying to share the URL. (A perfect defense is more difficult, and is probably unnecessary anyways; there's no way to prevent a user from personally transferring a file they downloaded to someone else.)
I'm developing a web app that sends the user an email notification to complete a lesson/tutorial. I've added the ability to automatically login the user via the link in that email. This featured has been added to several services around the internet, most notable, OkCupid.
Here's how I've set up my table:
+----+-------------+-------------------+-----------+--------------+----------------------+
| id | key (22) | secret (40) | user_id | action | expires |
+----+-------------+-------------------+-----------+--------------+----------------------+
| 1 | IbQlQW8Dn...| hdC4dXQJUPA0... | 1 | lesson/14 | 2013-06-21 16:28:55 |
+----+-------------+-------------------+-----------+--------------+----------------------+
When a user visits a link via the email, something like:
http://example.com/go/IbQlQW8Dn8PNXJFFwHQxwh/hdC4dXQJUPA0pU7I6eUiXawbnobYv0iThA
[http:/example.com/go/key/secret]
The server first checks that the url isn't expired based on the date in the table. If it isn't expired, the user is automatically logged in using the user_id and then redirected to the given url in the action column. I used two separate values (key & secret) for the url just for added security (prevent fusking).
Now because of the nature of the site (video lessons), security isn't a huge concern, but I'd still like to know what best practices to consider.
Should I limit the number of times a link can be used?
Currently I have the link expire 60 hours (3 days) from when the
email is sent. Should this be lowered?
Obvious two risks for unauthorized access include someone forwarding the email or someone gaining access to the user's email account. Anything else to consider?
Thanks for everyones insight, if this should be moved to another section of StackExchange, please let me know. I know I've seen other best practice post on here in the past.
Sending an auto-login link is fairly similar in risk to sending password-reset links in email and lots of sites do that.
This is a judgement call that you have to make. There's not a shared decision matrix that people use to decide what is and isn't an acceptable risk. What you're making here is more of a business decision, you're weighing the security risks versus ease of use (which can translate to more users and more business).
You need to ask the question 'What's the absolute worst thing in terms of site availability, business reputation and user experience that can happen if this feature is mis-used?'.
Additional things you should be concerned about:
People plucking your auto-login links of off of shared wifi networks
Auto-login links ending up in the logs of proxies between your server and the client
I recommend making the links single-use only or keeping the expiration time low. You should also put in monitoring that will alarm if a link is being overused.
You should also make sure you're not vulnerable to SQL injection when you take the secret and query the DB.
I pretty much agree with everything u2702 said in his answer, but you should also consider not allowing the user to change their password without confirming their current password if their current session was created from any form of autologin (cookie, link etc.). This can at least protect the user from getting locked out of their account by a changed password.
I think you’ve got all of the important stuff. I’d agree with everything #u2702 said and just add…
You might want to give users a way to invalidate their outstanding login links, or invalidate them automatically when they change their email address or password.
If the site sends out a lot of email, you can skip the database and encode the user, target, and expiration in the URL along with a signature. Amazon supports this for temporarily granting access to objects in S3 (http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html) and other sites use it for CSRF tokens. Pseudocode:
params = encode_qs(userid=1, target="lesson/14", expires=…)
url = "http://example.com/l/?" + params + "&" +
encode_qs(sig=hmac_sha1(secret, params))
(The secret you use to sign the request doesn't have to be unique per-email since it's not revealed.) This is no better than generating random keys, like you do, if you don't mind the load.
I don’t think you gain anything by limiting the number of times a link can be used before it expires (OkCupid doesn’t, some people hold onto the most recent email and use it more than once).
Does a separate “key” and “secret” give you any real extra security if they’re always used together?
I'm trying to create a private podcast feeds. Each user of my service gets an account and depending on what they pay, they will receive different content. Some content is sensitive so security is reasonably important; if any of the enclosed audio files made the rounds around the internet, it could be catastrophic for our business.
I am currently prototyping the service and MP3s are stored on S3 and they are not secured. It's time to secure them. From my research, I understand that I can, in fact, secure files on S3 with an access expiry period. But, because I have many users, signing the request with my "global" key and have an expiry probably isn't a good idea because
If I need to revoke access, I'll need to do it for everyone
Since I don't know when, exactly, their podcatcher will request the file, I don't know when to set the expiry. Sometimes, the podcatcher downloads the feed XML, but only later fetches the MP3 file so the URLs could expire before the client has a chance to fetch them (I'm thinking about iTunes, but there could be others).
The way I see it, I have two options and I'm not sure if either are workable:
Edit Another potential way, I suppose, would be to role my own security, and simply redirect to an MP3 on S3 with a short expiry if the user is good to go. This seems most sensible.
I can create user accounts on Amazon for ALL of my users and link them to an Amazon token in my database. Everyone's MP3 urls are signed with their secret token and expiry a long time from now. I don't like the idea of storing their tokens on my database, and I'm not sure if the Amazon ACL was designed for this scenario. It also means the files can still be shared if you know the URL.
I can proxy every request through my server. This means I only have one Amazon account, and I can role my own security system. But proxying every MP3 download through my server sounds slow, wasteful and expensive.
Any ideas on the best way to do this.
P.S. I'm not married to S3. Other solutions could be considered. And I'm on Heroku using Ruby, in case you care.
I am going with the redirect solution suggested elsewhere. This seems to give me the most flexibility and very low overhead. What you definitely should not do is is using links directly to S3 in your feed, because they likely expire before they are downloaded by the client.