Direct browser upload to Amazon S3 - php

I'm trying to figure out how perform a browser direct upload to Amazon S3 using an XHR. I'm using some pre-made code that creates a signature and performs the upload. All I have to do is enter my S3 security credentials. (For what it's worth, I want to do the policy signing using PHP).
I've forked the code to my GitHub account, you can find it here: https://github.com/keonr/direct-browser-s3-upload-example
As the readme file indicates, I have set my S3 bucket CORS to allow all origins, as such:
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Content-Type</AllowedHeader>
<AllowedHeader>x-amz-acl</AllowedHeader>
<AllowedHeader>origin</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Now, when I try to perform the file upload, the script returns with XHR Error and my browser's error console gives me a standard CORS error, saying that my Origin is now allowed for that XHR request. I've tried everything I can think of. I've chaned the * wildcard to the actual domain the request originates from to allowing the * wildcard to allowed headers. Nothing seems to work. It continues to produce that CORS error.
Can anyone help me get this off the ground and successfully complete a direct browser upload to S3? I don't care by which means, I just need to be able to get it done. Also, bear in mind that I am a novice when it comes to S3, so the more explicit the instructions, the better.
Thanks!

Try adding a wildcard for the AllowedHeader and allow all methods, like so:
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Great starting points for a direct upload to Amazon S3 are:
For the js:
http://www.designedbyaturtle.co.uk/2013/direct-upload-to-s3-with-a-little-help-from-jquery/
For the php:
http://birkoff.net/blog/post-files-directly-to-s3-with-php/
Or if you're looking for a solution that works out of the box, take a look at Plupload
Hope this gets you started!

Related

access to xmlhttprequest has been blocked by cors policy no 'access-control-allow-origin' [duplicate]

I am working on an app using Vue js.
According to my setting I need to pass to a variable to my URL when setting change.
<!-- language: lang-js -->
$.get('http://172.16.1.157:8002/firstcolumn/' + c1v + '/' + c1b, function (data) {
// some code...
});
But when my app hit on URL, it shows the following message.
Failed to load http://172.16.1.157:8002/firstcolumn/2017-03-01/2017-10-26: Redirect from 'http://172.16.1.157:8002/firstcolumn/2017-03-01/2017-10-26' to 'http://172.16.1.157:8002/firstcolumn/2017-03-01/2017-10-26/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.
In addition to what awd mentioned about getting the person responsible for the server to reconfigure (an impractical solution for local development) I use a change-origin chrome plugin like this:
Moesif Orign & CORS Changer (use to be free but now wants a work email address >_>)
Allow CORS: Access-Control-Allow-Origin
You can make your local dev server (ex: localhost:8080) to appear to be coming from 172.16.1.157:8002 or any other domain.
In case the 2nd plugin link breaks in the future or the plugin writer decides to capitalize off the fame of this thread, open your browser's
plugin marketplace and search "allow cors", there's going to be a
bunch of them.
Thanks all, I solved by this extension on chrome.
Allow CORS: Access-Control-Allow-Origin
If you have control over your server, you can use PHP:
<?PHP
header('Access-Control-Allow-Origin: *');
?>
Ask the person maintaining the server at http://172.16.1.157:8002/ to add your hostname to Access-Control-Allow-Origin hosts, the server should return a header similar to the following with the response-
Access-Control-Allow-Origin: yourhostname:port
Using npm:
To allow cross-origin requests install 'cors':
npm i cors
Add this in the server-side:
let cors = require("cors");
app.use(cors());
When you have this problem with Chrome, you don't need an Extension.
Start Chrome from the Console:
chrome.exe --user-data-dir="C:/Chrome dev session" --disable-web-security
Maybe you have to close all Tabs in Chrome and restart it.
I will assume that you're a front-end developer only and that you don't have access to the backend of the application (regarding the tags of the question).
Short answer on how to properly solve this in your case? You can't, you'll need somebody else.
What is this about?
You need to understand that CORS is a security thing, it's not just here to annoy you just for fun.
It's purpose is to mainly prevent the usage of a (malicious) HTTP call from a non-whitelisted frontend to your backend with some critical mutation.
You could give a look to this YouTube video or any other one really, but I recommend a visual video because text-based explanation can be quite hard to understand.
You also need to understand that if you use Postman or any other tool to try your API call, you will not get the CORS issue. The reason being that those tools are not Web frontends but rather some server-based tools.
Hence, don't be surprised if something is working there but not in your Vue app, the context is different.
Now, how to solve this?
Depending of the framework used by your backend team, the syntax may be quite different but overall, you'll need to tell them to provide something like Access-Control-Allow-Origin: http://localhost:3000 (or any other port you'll be using).
PS: Using Access-Control-Allow-Origin: * would be quite risky because it would allow anybody to access it, hence why a stricter rule is recommended.
If you're using a service, like an API to send SMS, payment, some Google console or something else really, you'll need to allow your localhost in the dashboard of the service. Ask for credentials to your manager or Tech Lead.
If you have access to the backend, you could it yourself as shown here (ExpressJS in this example): https://flaviocopes.com/cors/
How to hack it in a dirty way?
If you're in a damn hurry and want to get something really dirty, you could use a lot of various hacks a listed in the other answers, here's a quick list:
use any extension who is able to create a middleware and forward the request to the backend (it will work because it's not directly coming from your frontend)
force your browser to disable CORS, not sure how this would actually solve the issue
use a proxy, if you're using Nuxt2, #nuxtjs/proxy is a popular one but any kind of proxy (even a real backend will do the job)
any other hack related somehow to the 3 listed above...
At the end, solving the CORS issue can be done quite fast and easily. You only need to communicate with your team or find something on your side (if you have access to the backend/admin dashboard of some service).
I heavily do recommend trying get it right from the beginning because it's related to security and that it may be forgotten down the road...
The approved answer to this question is not valid.
You need to set headers on your server-side code
app.use((req,res,next)=>{
res.setHeader('Access-Control-Allow-Origin','*');
res.setHeader('Access-Control-Allow-Methods','GET,POST,PUT,PATCH,DELETE');
res.setHeader('Access-Control-Allow-Methods','Content-Type','Authorization');
next();
})
You can also try a chrome extension to add these headers automatically.
Hello If I understood it right you are doing an XMLHttpRequest to a different domain than your page is on. So the browser is blocking it as it usually allows a request in the same origin for security reasons. You need to do something different when you want to do a cross-domain request. A tutorial about how to achieve that is Using CORS.
When you are using postman they are not restricted by this policy. Quoted from Cross-Origin XMLHttpRequest:
Regular web pages can use the XMLHttpRequest object to send and receive data from remote servers, but they're limited by the same origin policy. Extensions aren't so limited. An extension can talk to remote servers outside of its origin, as long as it first requests cross-origin permissions.
To add the CORS authorization to the header using Apache, simply add the following line inside either the <Directory>, <Location>, <Files> or <VirtualHost> sections of your server config (usually located in a *.conf file, such as httpd.conf or apache.conf), or within a .htaccess file:
Header set Access-Control-Allow-Origin "*"
And then restart apache.
Altering headers requires the use of mod_headers. Mod_headers is enabled by default in Apache, however, you may want to ensure it's enabled.
I had the same problem in my Vue.js and SpringBoot projects. If somebody work with spring you can add this code:
#Bean
public FilterRegistrationBean simpleCorsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
// *** URL below needs to match the Vue client URL and port ***
config.setAllowedOrigins(Collections.singletonList("http://localhost:8080"));
config.setAllowedMethods(Collections.singletonList("*"));
config.setAllowedHeaders(Collections.singletonList("*"));
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean<>(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
I found solution in this article Build a Simple CRUD App with Spring Boot and Vue.js
You are making a request to external domain 172.16.1.157:8002/ from your local development server that is why it is giving cross origin exception.
Either you have to allow headers Access-Control-Allow-Origin:* in both frontend and backend or alternatively use this extension cors header toggle - chrome extension unless you host backend and frontend on the same domain.
Try running this command in your terminal and then test it again.
curl -H "origin: originHost" -v "RequestedResource"
Eg:
If my originHost equals https://localhost:8081/ and my RequestedResource equals https://example.com/
My command would be as below:
curl -H "origin: https://localhost:8081/" -v "https://example.com/"
If you can notice the following line then it should work for you.
< access-control-allow-origin: *
Hope this helps.
Do specify #CrossOrigin(origins = "http://localhost:8081")
in Controller class.
You can solve this temporarily by using the Firefox add-on, CORS Everywhere. Just open Firefox, press Ctrl+Shift+A , search the add-on and add it!
You won't believe this,
Make sure to add "." at the end of the "url"
I got a similar error with this code:
fetch(https://itunes.apple.com/search?term=jack+johnson)
.then( response => {
return response.json();
})
.then(data => {
console.log(data.results);
}).catch(error => console.log('Request failed:', error))
The error I got:
Access to fetch at 'https://itunes.apple.com/search?term=jack+johnson'
from origin 'http://127.0.0.1:5500' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested
resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
But I realized after a lot of research that the problem was that I did not copy the
right URL address from the iTunes API documentation.
It should have been
https://itunes.apple.com/search?term=jack+johnson.
not
https://itunes.apple.com/search?term=jack+johnson
Notice the dot at the end
There is a huge explanation about why the dot is important quoting issues about DNS and character encoding but the truth is you probably do not care. Try adding the dot it might work for you too.
When I added the "." everything worked like a charm.
I hope it works for you too.
install:
npm i cors
Then include cors():
app.get("/list",cors(),(req,res) =>{
});
In addition to the Berke Kaan Cetinkaya's answer.
If you have control over your server, you can do the following in ExpressJs:
app.use(function(req, res, next) {
// update to match the domain you will make the request from
res.header("Access-Control-Allow-Origin", "YOUR-DOMAIN.TLD");
res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
https://enable-cors.org/server_expressjs.html
I tried this code,and that works for me.You can see the documentation in this link
var io = require("socket.io")(http, {
cors: {
origin: "*",
methods: ["GET", "POST"]
}
})
The reason that I came across this error was that I hadn't updated the path for different environments.
you have to customize security for your browser or allow permission through customizing security. (it is impractical for your local testing)
to know more about please go through the link.
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
These errors may be caused due to follow reasons, ensure the following steps are followed. To connect the local host with the local virtual machine(host). Here, I'am connecting http://localhost:3001/ to the http://abc.test Steps to be followed:
1.We have to allow CORS, placing Access-Control-Allow-Origin: in header of request
may not work. Install a google extension which enables a CORS request.*
2.Make sure the credentials you provide in the request are valid.
3.Make sure the vagrant has been provisioned. Try vagrant up --provision this make the localhost connect to db of the homestead.
Try changing the content type of the header. header:{ 'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8;application/json' }
this point is very important.
Another solution to this problem in a specific scenario :
If
AWS APIGW is your backend with authentication enabled and
authentication fails,
your browser may end up complaining about CORS even if CORS is enabled in APIGW. You also need to enable CORS for 4XX as follows
API:YourAPI > Resources > /YourResource > Actions > Enable CORS > Gateway Responses for yourAPI check Default 4XX
Authentication will still fail but it won't look like CORS is the root cause
$.get('https://172.16.1.157:8002/firstcolumn/' + c1v + '/' + c1b, function (data) {
// some code...
});
Just put "https" .

Error 409 when copy Azure Blob file within container with PHP

Using PHP to connect to Azure blob storage account. Using azure-storage-php ( github )
For the copy i use BlobRestProxy.copyBlob() using the api.
I am able to connect to the azure blob storage. Able to upload, list, delete blob files. But not able to copy the blob file within the same container. Does anyone has an example of how to copy a blob file within php using azure-storage-php or does anyone recognizes the error?
I already tried it with several blob storage account settings (public and not). For authentication i use a Shared Access Signature. The weird thing is that i am able to do alle things like create, read and delete but copy does give the below error. Thanks in advance.
The storage account is new, created at 3-12-2021
Fail:
Code: 409
Value: Public access is not permitted on this storage account.
details (if any): <?xml version="1.0" encoding="utf-8"?><Error><Code>CannotVerifyCopySource</Code><Message>Public access is not permitted on this storage account.
RequestId:4b324b08-b01e-0009-6c1e-1187a1000000
Time:2022-01-24T12:30:35.8956602Z</Message></Error>.
Thanks for the reply allready!
The Shared Access Signature specified on the request applies only to the destination blob while using Copy Blob
Access to the source blob is authorized separately
If you are using the shared key (Storage Account Key), the authorization would have been done with the same key
As you are using Shared Access Signature, you need to append the SAS token in the x-ms-copy-source in the request
Thanks to RamaraoAdapa-MT, your answer was very helpfull. The developer has fixed the problem now.
And it was indeed the case that if you use the storage account key the copy is done with the same key. Public access is not necessery in both cases (SAS or AccountKey)

How to access public AWS S3 bucket in laravel

I have a public S3 bucket called latheesan-public-bucket (for example) in AWS in the eu-west-1 region.
If I were to visit the following url in the browser (for example):
https://latheesan-public-bucket.s3-eu-west-1.amazonaws.com/
I get the following XML showing that I have one file in the bucket:
<?xml version="1.0" encoding="UTF-8"?>
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Name>latheesan-public-bucket</Name>
<Prefix />
<Marker />
<MaxKeys>1000</MaxKeys>
<IsTruncated>false</IsTruncated>
<Contents>
<Key>test.json</Key>
<LastModified>2017-07-11T16:39:50.000Z</LastModified>
<ETag>"056f32ee5cf49404607e368bd8d3f2af"</ETag>
<Size>17658</Size>
<StorageClass>STANDARD</StorageClass>
</Contents>
</ListBucketResult>
If I were to then visit https://latheesan-public-bucket.s3-eu-west-1.amazonaws.com/test.json I can download my file from my public bucket.
In order to achieve the same in my Laravel application; I first added this package via composer:
league/flysystem-aws-s3-v3
Then on my .env I've added the following lines:
AWS_REGION=eu-west-1
AWS_BUCKET=latheesan-public-bucket
Lastly, I then tried to use the laravel filesystem to access the public s3 bucket file like this:
$json = Storage::disk('s3')->get('test.json');
When I did this; I got the following error:
Error retrieving credentials from the instance profile metadata
server. (cURL error 28: Connection timed out after 1000 milliseconds
(see http://curl.haxx.se/libcurl/c/libcurl-errors.html))
So, I updated my .env with some fake credentials:
AWS_KEY=123
AWS_SECRET=123
AWS_REGION=eu-west-1
AWS_BUCKET=latheesan-public-bucket
Now I get this error:
Illuminate \ Contracts \ Filesystem \ FileNotFoundException
test.json
So my question is; firstly what am I doing wrong here? Is there no way to access a public s3 bucket in laravel without actually providing a valid S3 Key/secret? what if I don't know them? I only have the url to the public s3 bucket.
P.S. the latheesan-public-bucket does not exist (it was a dummy bucket name to explain my problem, I do have a real public bucket I am trying to work with and it works fine in browser as explained above).
When you try to access it via the HTTPS URL, it works because it is public, and you're
When you try to access it via the SDK, it is trying to use the API to access it.
So either give your instance profile the correct permissions to access the bucket (which would no longer need to be public) or simply use an http client to retrieve the file.
If you use the S3 API to access your bucket, AWS credentials are required. The reasons is that the API needs to sign the S3 request.

Where should I create uploads folder and place upload.php while implementing ng2 file upload in localhost:4200

I have implemented ng2 file upload on my server.
It asks for an API URL and I have provided it. Everything works online as expected. But I want to run it locally for further implementation.
This is my upload api URL:
const URL = 'http://example.com/v8/products-api/upload2.php';
In upload2.php the path is given as $path = 'uploads/';.
My question is, where shall I create this folder and where shall I place this php file ?
I am unable to upload a file to server from http:localhost:4200 as it gives the following error:
XMLHttpRequest cannot load http://funiks.com/adminv8/products-api/upload2.php. Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:4200' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
My php includes header("Access-Control-Allow-Origin: *");
I'm no PHP expert, so I can't attest to the CORS configuration of your server. But reading the error you're getting it looks like you can't use a wildcard, so why not try setting your headers like so...
header('Access-Control-Allow-Origin: http://localhost:4200', false);
Also you could try using the Angular Jsonp library rather than the Http. The functions will stay exactly the same, however you do open up some security concerns by doing so...
(P.S. If you use the Jsonp library, just add &callback=JSONP_CALLBACK to the end of your API url)

Security error accessing url in MXML

I am calling http service from flex ...
<mx:HTTPService id="personRequest" url="http://111.111.1.11/idesk/user.php/userinfo" useProxy="false" resultFormat="text" result="personJSON(event)" fault="anotherMethod(event)" method="post">
<mx:request xmlns="">
<getPerson>"true"</getPerson>
</mx:request>
</mx:HTTPService>
and getting following error:
Security error accessing url
I have placed cross-domain policy file in server-script folder but it didnt solve my problem.
Any help is appreciated. Thanks in advance.
Try to use Charles to see of what flash trying to load. It will show if swf accessed crossdomain.xml from your server and correct path.
Are you loading from your file system? If so, you must be able to see in your address bar something like "file:// ..."
If that is the case, the Flash Player will not allow you to connect to servers (even though you have configured your cross-domain.xml)
You have two possible solutions to solve this problem:
Host your Flex Application in a web server (your address will look like http:[something])
Add the -use-network=false in your Flex compiler arguments.
You can find more information about Flex Compiler arguments here
I hope this helps.

Categories