AWS S3 Stop Download Image automatically when browsed via URL - amazon-web-services

I am uploading images to my S3 bucket via my Node.js Application. I have the following bucket policy.
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "AllowPublicRead",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucket_name/*"
}
]
}
When I go to the link of the file lets say its an image. It automatically downloads as a file and does not render in the browser. Any idea how to make it display in the browser without automatically force downloading the image in the browser?

Explicitly set the Content-Type of the object with image/<appropriate-subtype>.
var params = { Bucket: '', Key: '', ContentType: 'image/png', ... }
The default Content-Type would be application/octet-stream, thus instead of rendering in the browser it is being downloaded.

Related

AWS S3 | Access Denied while requesting image by URL | .Net Core

We have a S3 Bucket where we have stored images and we want to show these image on our Angular component by using image URL. But when we hit the URL , we are getting this error
Error:
Requests specifying Server Side Encryption with AWS KMS managed keys
require AWS Signature Version 4.
How can we load these images on our Angular component using URLs ??
Note: We are hosting this application on Elastic Beanstalk using .Net core project.
Here is the bucket policy:
{
"Version": "2012-10-17",
"Id": "BUCKETPOLICY",
"Statement": [
{
"Sid": "DenyInsecureAccess",
"Effect": "Deny",
"Principal": "*",
"Action": "*",
"Resource": [
"arn:aws:s3:::dev-productimages",
"arn:aws:s3:::dev-productimages/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
Here is Encryption configuration:
When you upload the file, you need to set the acl to public read access
https://docs.aws.amazon.com/sdkfornet1/latest/apidocs/html/T_Amazon_S3_Model_S3CannedACL.htm
Example:
var transferUtilityRequest = new TransferUtilityUploadRequest()
{
InputStream = file.OpenReadStream(),
Key = trustedStorageName,
BucketName = bucketName,
CannedACL = S3CannedACL.PublicRead, // Ensure the file is read-only to allow users view their pictures
PartSize = 6291456
};
You're denying insecure access, but where are you granting access?
Without explicitly granting public access, your objects are accessible only to authenticated users from the owner account. I would rewrite as follows:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAnonymousAccess",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": [
"arn:aws:s3:::dev-productimages/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "true"
}
}
}
]
}
Very important: note that I changed the action to s3:GetObject.

How to load a website via s3 with pre-signed URL

I would like to block public access to my webapp served via S3 and only allow pre-signed URL to load the website. To do this I have allowed static site hosting in S3, and allowed public read to all objects. This allowed me to load the website public. Then I added a policy to deny access to index.html:
{
"Version": "2008-10-17",
"Id": "PolicyForPublicWebsiteContent",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::web-portal/*"
},
{
"Sid": "PrivateReadGetObject",
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::web-portal/index.html"
}
]
}
Thereafter I generated a pre-signed URL to the index.html page via using the sdk.
const url = s3.getSignedUrl('getObject', {
Bucket: 'web-portal',
Key: 'index.html',
Expires: signedUrlExpireSeconds
})
However, I get access denied when I try to access the URL provided via the SDK.
I assume this happens as I added the deny policy to index.html. I would be much obliged to know what is the proper way to implement such a feature with aws s3.
This was resolved by only adding the policy to allow other files (js, css) to be accessed publicly, and not adding any policy (Allow/Deny) to the index.html.
For me all my other files we located under the folder called static. Therefore I added a policy to allow public access to this folder.
{
"Version": "2008-10-17",
"Id": "PolicyForPublicWebsiteContent",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::web-portal/static/*"
}
]
}
After adding the above policy you cannot access the index.html page via browser. However you can access the index.html if you have a pre-signed URL. As the other required files are in public domain, the index.html was able to load the rest.
I pressume the same can be done if we can gzip the entier website. Thus all files will reside in one single zip folder. Then provide a pre-signed url to that file. In this way we do not have to enter any bucket policies for other non index files.

How to download aws s3 files from client side without IAM, but only IP restriction?

I'm new to s3 and here's what I got:
I have the URL of s3 some files in my db and I want to download them in my client app with that URL (e.g. https://my_s3_bucket_name.s3.amazonaws.com/sample_2-1591371022041.pdf).
I don't want to make it public to everyone but I don't want to make it available to only my IAM. Instead, I want to open to public to my client side web app url. i.e the file should only downloadable when the url is called from from http://my_client_app.com
I took reference form this and made a public policy for my public ip (and the ip address of where I host http://my_client_app.com) but it doesn't seems working, when I open the File URL from my browser I still get 403 forbidden.
my bucket policy:
{
"Version": "2012-10-17",
"Id": "S3PolicyId1",
"Statement": [
{
"Sid": "IPAllow",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::my_bucket_name_hellobucket/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"my_public_ip/24",
"my_aws_ec2_ip/24"
]
}
}
}
]
}
ps1: if I set read access to public, i'm able to download the file with the file URL
ps2: can anyone tell me what the "Id" means / when will it be used in the bucket policy?
Thanks!
Based on OP's feedback in the comment, setting "Principal": "*" should allow anonymous access.

When I click "Open in new tab" on my S3 images, it downloads the image instead

Here's my bucket policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Allow All",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-bucket/*"
},
{
"Sid": "Deny All Actions On All But Media and Static Unless Defined User",
"Effect": "Deny",
"NotPrincipal": {
"AWS": "arn:aws:iam::**********:root"
},
"Action": "s3:*",
"NotResource": [
"arn:aws:s3:::my-bucket/media/*",
"arn:aws:s3:::my-bucket/static/*"
]
}
]
}
So basically I have 3 folders: backup, static and media. All the objects in my media and static folders are public.
However when I click on the full path, for example this object: https://s3.us-east-2.amazonaws.com/my-bucket/media/x12wHSRoM9szjvY (this obj doesn't actually exist but the path is the same format) there is no .jpg or .png extension even though it is an image. Could this be the reason for my problem and if so, how can I fix this so I can access the raw object and not download it when I click on it?
An object stored in Amazon S3 can also have Metadata. This metadata identifies the type of file that is stored, eg image/jpeg.
When the AWS Command-Line Interface (CLI) uploads a file, it typically sets the Metadata values, so it should work fine.
However, if your method of uploading does not set the Metadata values, then the browser has no way of knowing the type of file. It will then offer to download the file rather than displaying it. (The filename extensions such as .png and .jpg don't actually set the file type.)
See: How Do I Add Metadata to an S3 Object? - Amazon Simple Storage Service

Can I set a policy for certain file in an S3 bucket?

I have an S3 bucket "mybucket" with loads of files in it for example:
upload1/123.jpg
public/353.jpg
public/123.jpg
upload2/33.jpg
upload3/423.jpg
As I understand it the folders are just a convenience and are just objects anyways. So is it possible to make all the public/* objects public but not the others? How can I do this?
EDIT:
I've done so more reading, would something like this work and not affect anything else?
{
"Id": "Policy1415732583092",
"Statement": [
{
"Sid": "Stmt1415732573054",
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::mybucket/public/*",
"Principal": {
"AWS": [
"*"
]
}
}
]
}
Yes this works just fine. You can add this policy to your bucket permissions:
{
"Version": "2012-10-17",
"Id": "123",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:**",
"Resource": "arn:aws:s3:::mybucket/public/*"
}
]
}
Then add a file called test.html to your public folder and one of your private folders:
<html>
<body>
test
</body>
</html>
Then enable static web hosting on the s3 bucket and then go to the S3 endpoint in a web browser (for me in US Standard this would be: http://s3.amazonaws.com/mybucket/public/test.html) and you will see the web page displayed, but when you try to access this page through the private bucket you will see that it fails.