Bezpośrednie przesyłanie plików Amazon S3 z przeglądarki klienta - ujawnienie klucza prywatnego

Implementuję bezpośrednie przesyłanie plików z KOMPUTERA Klienta do Amazon S3 przez REST API przy użyciu tylko JavaScript, bez kodu po stronie serwera. Wszystko działa dobrze, ale jedno mnie martwi...

Kiedy wysyłam zapytanie do Amazon S3 REST API, muszę je podpisać i umieścić podpis w nagłówku Authentication. Aby stworzyć podpis, muszę użyć mojego tajnego klucza. Ale wszystko dzieje się po stronie klienta, więc tajny klucz można łatwo ujawnić ze źródła strony (nawet jeśli zaciemniam / szyfruję mój źródła).

Jak mam sobie z tym poradzić? Czy to w ogóle problem? Może mogę ograniczyć użycie określonego klucza prywatnego tylko do wywołań REST API z określonego źródła CORS i tylko do metod PUT and POST lub może połączyć klucz tylko do S3 i konkretnego bucket? Może istnieją inne metody uwierzytelniania?

Rozwiązanie" Bezserwerowe " jest idealne, ale mogę rozważyć włączenie przetwarzania po stronie serwera, z wyłączeniem przesłania pliku na mój serwer, a następnie wysłania na S3.

Author: Rory, 2013-07-11

8 answers

Myślę, że to, czego chcesz, to przesyłanie przez przeglądarkę za pomocą posta.

Zasadniczo potrzebujesz kodu po stronie serwera, ale wszystko, co robi, to generuje podpisane Zasady. Gdy kod po stronie klienta ma podpisaną politykę, może przesłać za pomocą POST bezpośrednio do S3 bez danych przechodzących przez serwer.

Oto oficjalne linki do doc:

Diagram: http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingHTTPPOST.html

Przykładowy kod: http://docs.aws.amazon.com/AmazonS3/latest/dev/HTTPPOSTExamples.html

Podpisana polityka będzie w Twoim html w postaci takiej jak Ta:

<html>
  <head>
    ...
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    ...
  </head>
  <body>
  ...
  <form action="http://johnsmith.s3.amazonaws.com/" method="post" enctype="multipart/form-data">
    Key to upload: <input type="input" name="key" value="user/eric/" /><br />
    <input type="hidden" name="acl" value="public-read" />
    <input type="hidden" name="success_action_redirect" value="http://johnsmith.s3.amazonaws.com/successful_upload.html" />
    Content-Type: <input type="input" name="Content-Type" value="image/jpeg" /><br />
    <input type="hidden" name="x-amz-meta-uuid" value="14365123651274" />
    Tags for File: <input type="input" name="x-amz-meta-tag" value="" /><br />
    <input type="hidden" name="AWSAccessKeyId" value="AKIAIOSFODNN7EXAMPLE" />
    <input type="hidden" name="Policy" value="POLICY" />
    <input type="hidden" name="Signature" value="SIGNATURE" />
    File: <input type="file" name="file" /> <br />
    <!-- The elements after this will be ignored -->
    <input type="submit" name="submit" value="Upload to Amazon S3" />
  </form>
  ...
</html>

Zauważ, że akcja formularza wysyła plik bezpośrednio do S3 - nie za pośrednictwem serwera.

Za każdym razem, gdy jeden z Twoich użytkowników chce przesłać plik, tworzysz POLICY i SIGNATURE na swoim serwerze. Zwracasz stronę do przeglądarki użytkownika. Użytkownik może następnie przesłać plik bezpośrednio do S3 bez przechodzenia przez serwer.

Podpisując polisę, zwykle powoduje, że polisa wygasa po kilku minutach. Zmusza to Użytkowników do rozmowy z serwerem przed przesłaniem. Pozwala to monitorować i ograniczać przesyłanie, jeśli chcesz.

Jedynymi danymi wchodzącymi do lub z serwera są podpisane adresy URL. Twoje tajne klucze pozostają tajne na serwerze.

 191
Author: secretmike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-17 02:15:19

Możesz to zrobić przez AWS S3 Cognito wypróbuj ten link tutaj:

Http://docs.aws.amazon.com/AWSJavaScriptSDK/guide/browser-examples.html#Amazon_S3

Wypróbuj również ten kod

Po prostu zmień Region, IdentityPoolId i nazwę wiadra

<!DOCTYPE html>
<html>

<head>
    <title>AWS S3 File Upload</title>
    <script src="https://sdk.amazonaws.com/js/aws-sdk-2.1.12.min.js"></script>
</head>

<body>
    <input type="file" id="file-chooser" />
    <button id="upload-button">Upload to S3</button>
    <div id="results"></div>
    <script type="text/javascript">
    AWS.config.region = 'your-region'; // 1. Enter your region

    AWS.config.credentials = new AWS.CognitoIdentityCredentials({
        IdentityPoolId: 'your-IdentityPoolId' // 2. Enter your identity pool
    });

    AWS.config.credentials.get(function(err) {
        if (err) alert(err);
        console.log(AWS.config.credentials);
    });

    var bucketName = 'your-bucket'; // Enter your bucket name
    var bucket = new AWS.S3({
        params: {
            Bucket: bucketName
        }
    });

    var fileChooser = document.getElementById('file-chooser');
    var button = document.getElementById('upload-button');
    var results = document.getElementById('results');
    button.addEventListener('click', function() {

        var file = fileChooser.files[0];

        if (file) {

            results.innerHTML = '';
            var objKey = 'testing/' + file.name;
            var params = {
                Key: objKey,
                ContentType: file.type,
                Body: file,
                ACL: 'public-read'
            };

            bucket.putObject(params, function(err, data) {
                if (err) {
                    results.innerHTML = 'ERROR: ' + err;
                } else {
                    listObjs();
                }
            });
        } else {
            results.innerHTML = 'Nothing to upload.';
        }
    }, false);
    function listObjs() {
        var prefix = 'testing';
        bucket.listObjects({
            Prefix: prefix
        }, function(err, data) {
            if (err) {
                results.innerHTML = 'ERROR: ' + err;
            } else {
                var objKeys = "";
                data.Contents.forEach(function(obj) {
                    objKeys += obj.Key + "<br>";
                });
                results.innerHTML = objKeys;
            }
        });
    }
    </script>
</body>

</html>
Aby uzyskać więcej informacji, sprawdź - Github
 32
Author: Joomler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-20 08:23:00

Mówisz, że chcesz rozwiązania "bezserwerowego". Ale to oznacza, że nie masz możliwości wprowadzenia żadnego" swojego " kodu w pętli. (Uwaga: po przekazaniu kodu Klientowi, jest to teraz " ich " kod.) Blokowanie CORS nie pomoże: ludzie mogą łatwo napisać narzędzie nie-internetowe (lub internetowe proxy), które dodaje poprawny nagłówek CORS, aby nadużywać systemu.

Duży problem polega na tym, że nie można odróżnić różnych użytkowników. Nie możesz pozwolić jednemu użytkownikowi na listę / dostęp do jego plików, ale uniemożliwiają to innym. Jeśli wykryjesz nadużycie, nie możesz nic z tym zrobić, poza zmianą klucza. (Które napastnik może prawdopodobnie po prostu dostać ponownie.)

Najlepiej jest utworzyć "iam user" z kluczem do klienta javascript. Daj mu tylko dostęp do zapisu tylko do jednego wiadra. (ale najlepiej, nie włączaj operacji ListBucket, która uczyni ją bardziej atrakcyjną dla atakujących.)

Jeśli masz serwer (nawet prostą instancję micro za $ 20 / miesiąc), możesz może podpisać klucze na serwerze podczas monitorowania / zapobiegania nadużyciom w czasie rzeczywistym. Bez serwera najlepsze, co możesz zrobić, to okresowo monitorować nadużycia po fakcie. Oto co bym zrobił:

1) okresowo obracaj klucze dla tego użytkownika IAM: co noc Generuj nowy klucz dla tego użytkownika IAM i zastępuj najstarszy klucz. Ponieważ są 2 klucze, każdy klucz będzie ważny przez 2 dni.

2) Włącz logowanie S3 i pobieraj logi co godzinę. Ustaw alerty na "zbyt wiele przesłanych" i "za dużo pobrań". Będziesz chciał sprawdzić zarówno całkowity Rozmiar Pliku, jak i liczbę przesłanych plików. Będziesz chciał monitorować zarówno sumy globalne, jak i sumy na adres IP (z niższym progiem).

Te kontrole można wykonać "bezserwerowo", ponieważ można je uruchomić na pulpicie. (tzn. S3 wykonuje całą pracę, te procesy tylko po to, aby ostrzec Cię o nadużyciu wiadra S3, abyś nie dostał gigantycznego rachunku AWS pod koniec miesiąca.)

 15
Author: BraveNewCurrency,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-14 14:19:47

Dodając więcej informacji do zaakceptowanej odpowiedzi, możesz odwołać się do mojego bloga, aby zobaczyć uruchomioną wersję kodu, używając AWS Signature version 4.

Podsumujemy tutaj:

Jak tylko użytkownik wybierze plik do przesłania, wykonaj następujące czynności: 1. Wykonaj połączenie z serwerem WWW, aby zainicjować usługę generowania wymaganych params

  1. W tym serwisie wykonaj połączenie z serwisem AWS IAM, aby uzyskać tymczasową wiarygodność

  2. Po uzyskaniu cred Utwórz politykę bucket (base 64 encoded string). Następnie podpisz Zasady wiadra tymczasowym tajnym kluczem dostępu, aby wygenerować ostateczny podpis

  3. Wyślij niezbędne parametry z powrotem do interfejsu

  4. Po odebraniu, Utwórz obiekt formularza html, ustaw wymagane params i opublikuj go.

Aby uzyskać szczegółowe informacje, zapoznaj się https://wordpress1763.wordpress.com/2016/10/03/browser-based-upload-aws-signature-version-4/

 6
Author: RajeevJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-03 09:50:29

Aby stworzyć podpis, muszę użyć mojego tajnego klucza. Ale wszystko dzieje się po stronie klienta, więc tajny klucz można łatwo ujawnić ze źródła strony (nawet jeśli zaciemniam / szyfruję moje źródła).

Tutaj źle zrozumiałeś. Podpisy cyfrowe są używane po to, aby można było zweryfikować coś jako poprawne bez ujawniania tajnego klucza. W takim przypadku podpis cyfrowy jest używany, aby uniemożliwić użytkownikowi modyfikację zasad ustawionych dla formularz post.

Podpisy cyfrowe, takie jak ten tutaj, są używane dla bezpieczeństwa w całej sieci. Jeśli ktoś (NSA?) naprawdę byli w stanie je złamać, mieliby znacznie większe cele niż Twoje wiadro S3:)

 4
Author: OlliM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-25 11:38:42

Jeśli nie masz żadnego kodu po stronie serwera, Twoje bezpieczeństwo zależy od bezpieczeństwa dostępu do kodu JavaScript po stronie klienta(czyli każdy, kto ma kod może coś wgrać).

Więc polecam, aby po prostu utworzyć specjalne wiadro S3, które jest publiczne do zapisu (ale nie do odczytu), więc nie potrzebujesz żadnych podpisanych komponentów po stronie klienta.

Nazwa wiadra (np. GUID) będzie twoją jedyną obroną przed złośliwym uploadem (ale potencjalny napastnik może nie używaj wiadra do przesyłania danych, ponieważ jest to zapis tylko do niego)

 2
Author: Ruediger Jungbeck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-08 16:46:48

Podałem prosty kod, aby przesłać pliki z przeglądarki Javascript do AWS S3 i wyświetlić listę wszystkich plików w wiadrze S3.

Kroki:

  1. Aby wiedzieć, jak stworzyć Create IdentityPoolId http://docs.aws.amazon.com/cognito/latest/developerguide/identity-pools.html

    1. Wejdź na stronę konsoli S3 i otwórz konfigurację cors z właściwości bucket i zapisz do niej następujący kod XML.

      <?xml version="1.0" encoding="UTF-8"?>
      <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
       <CORSRule>    
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>DELETE</AllowedMethod>
        <AllowedMethod>HEAD</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
       </CORSRule>
      </CORSConfiguration>
      
    2. Tworzenie pliku HTML zawierający następujący kod Zmień poświadczenia, otwórz plik w przeglądarce i ciesz się.

      <script type="text/javascript">
       AWS.config.region = 'ap-north-1'; // Region
       AWS.config.credentials = new AWS.CognitoIdentityCredentials({
       IdentityPoolId: 'ap-north-1:*****-*****',
       });
       var bucket = new AWS.S3({
       params: {
       Bucket: 'MyBucket'
       }
       });
      
       var fileChooser = document.getElementById('file-chooser');
       var button = document.getElementById('upload-button');
       var results = document.getElementById('results');
      
       function upload() {
       var file = fileChooser.files[0];
       console.log(file.name);
      
       if (file) {
       results.innerHTML = '';
       var params = {
       Key: n + '.pdf',
       ContentType: file.type,
       Body: file
       };
       bucket.upload(params, function(err, data) {
       results.innerHTML = err ? 'ERROR!' : 'UPLOADED.';
       });
       } else {
       results.innerHTML = 'Nothing to upload.';
       }    }
      </script>
      <body>
       <input type="file" id="file-chooser" />
       <input type="button" onclick="upload()" value="Upload to S3">
       <div id="results"></div>
      </body>
      
 2
Author: Nilesh Pawar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-27 10:18:37

Jeśli chcesz skorzystać z usługi 3rd party, auth0.com wspiera tę integrację. Usługa auth0 wymienia uwierzytelnianie usługi SSO innej firmy na token sesji tymczasowej AWS będzie miał ograniczone uprawnienia.

Zobacz: https://github.com/auth0-samples/auth0-s3-sample/
i dokumentacji auth0.

 0
Author: Jason,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-03 07:42:36