CulturalMe / meteor-slingshot

Upload files directly to AWS S3, Google Cloud Storage and others in meteor
MIT License
594 stars 105 forks source link

Support for private files via pre-signed URLs #214

Open macsj200 opened 7 years ago

macsj200 commented 7 years ago

Hello, I'd like to start off by thanking the maintainers for their hard work on this package. It's a very solid piece of software that has saved me a lot of time 😃.

Would it be possible to add pre-signed URL support? I would like to restrict viewing of files, and the SO question I asked about doing this kind of thing pointed to pre-signed URLs as the way to go.

ping @wesleyfsmith

adamgins commented 7 years ago

@macsj200 wondering which way you went here? ie did you just go with aws-sdk and pre-signed URLs? http://docs.aws.amazon.com/AmazonS3/latest/dev/PresignedUrlUploadObject.html

sferoze commented 7 years ago

@macsj200 @adamgins did you get pre-sign url's working?

I have been dealing with this issue too. With this package, it seems that you HAVE to make the URL's completely public and anyone with the URL can view the file. I don't see any other way at the moment. Because the client is uploading directly to s3 they receive back a public URL.

That means the security of the uploaded file depends on keeping the URL private.

But how can we make this URL only accessible by certain users? Such that if the download URL is posted on a random site, it will not work.

Seems like pre-signed URL is the way to go, but I am not sure how to implement this with Slingshot.

If possible can you give me a rough idea of how to do this...

Thanks

resmith commented 6 years ago

The issue is not pre-signed URL for download. Once it is in S3 you can generate a preSigned URL for download. Slingshot merely puts the object in the S3 bucket.

The issue is using a pre-signed URL with S3 to upload to the bucket.

sasikanth513 commented 6 years ago

Using following i'm able to restrict "GET" access to only my website, so even though people have the url they can't see the file by entering url in the browser, requests should come from my website.

Of course people can open console and do some hacky stuff to make it look like request coming from my my website but my platform used by only few sales people so I don't worry about this case much

here my s3 config

CORS CONFIG

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

I removed get allowmethod which is suggested by slingshot in the readme, so get request is not public

Bucket Policy

{
    "Version": "2012-10-17",
    "Id": "http referer policy",
    "Statement": [
        {
            "Sid": "Allow get requests originated from my sites",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::bucket-name/*",
            "Condition": {
                "StringLike": {
                    "aws:Referer": [
                        "https://platform.myapp.com/*",
                        "http://localhost:3000/*"
                    ]
                }
            }
        },
        {
            "Sid": "Explicit deny to ensure requests are allowed only from specific referer.",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::bucket-name/*",
            "Condition": {
                "StringNotLike": {
                    "aws:Referer": [
                        "https://platform.myapp.com/*",
                        "http://localhost:3000/*"
                    ]
                }
            }
        }
    ]
}

with this i'm able to restrict get access to only myapp, hope this helps someone out there.

If there are any other improvements I can do to this policy please let me know.

EDIT

Everything works fine even without the first statement from bucket policy

Bucket Policy

{
    "Version": "2012-10-17",
    "Id": "http referer policy",
    "Statement": [
        {
            "Sid": "Explicit deny to ensure requests are allowed only from specific referer.",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::bucket-name/*",
            "Condition": {
                "StringNotLike": {
                    "aws:Referer": [
                        "https://platform.myapp.com/*",
                        "http://localhost:3000/*"
                    ]
                }
            }
        }
    ]
}