0

I'm generating a SAS token for every successful blob upload to Azure storage account and able to view file in browser using URL. But when I change the file names in the URL, I'm able to view another file with same token.

How can we prevent this happening without adding unique identifier?

Thank you in advance!

This is what I am doing to generate SAS token for every successful upload.

public class generateURL extends MbJavaComputeNode {

    public void evaluate(MbMessageAssembly inAssembly) throws MbException {
        MbOutputTerminal out = getOutputTerminal("out");
        MbMessage inMessage = inAssembly.getMessage();
        MbMessageAssembly outAssembly = new MbMessageAssembly(inAssembly, 
                inAssembly.getLocalEnvironment(),
                inAssembly.getExceptionList(),
                inAssembly.getMessage());
        MbElement env = inAssembly.getGlobalEnvironment().getRootElement() ;
        String fileName= env.getFirstElementByPath("Variables/fileName").getValueAsString();
        String accountName= env.getFirstElementByPath("Variables/accountName").getValueAsString();
        String containerName= env.getFirstElementByPath("Variables/containerName").getValueAsString();
        String storageKey= env.getFirstElementByPath("Variables/storageKey").getValueAsString();
        //String uniqueIdentifier= env.getFirstElementByPath("Variables/uniqueIdentifier").getValueAsString();
        String resourceUrl = "https://"+accountName+".blob.core.windows.net/"+containerName+"/"+fileName;
        try {
            // create new message as a copy of the input
            MbMessage outMessage = new MbMessage(inMessage);
            outAssembly = new MbMessageAssembly(inAssembly, outMessage);
            // ----------------------------------------------------------
            // Add user code below
            Calendar calendar = Calendar.getInstance();
            Date start = calendar.getTime();
            Date expiry = new Date(start.getTime() + 3600 * 1000); // 1 hour from now
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
            dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
            
            
            String signedPermissions = "r"; //read and list
            String signedService = "b";  //blob
            String signedResource = "c";  //service, container, objects
            String canonicalizedResource = "/blob/"+accountName+"/"+containerName+"/"+fileName;
            String startTimeString = (dateFormat.format(start));
            String expiryTimeString = (dateFormat.format(expiry));
            String protocol = "https";
            String signedVersion = "2015-04-05";
            String signedIP = "";
            String rscc = "";  //Cache-Control
            String signedIdentifier = "";  //Cache-Control
            String rscd = "";  //Content-Disposition               
            String rsce = "";  //Content-Encoding
            String rscl = "";  //Content-Language
            String rsct = "binary";  //Content-Type      binary
                
            
            String stringToSign = signedPermissions + "\n" +  
                    startTimeString + "\n" +  
                    expiryTimeString + "\n" +  
                    canonicalizedResource + "\n" +  
                    signedIdentifier + "\n" +  
                    signedIP + "\n" +  
                    protocol + "\n" +  
                    signedVersion + "\n" +  
                    rscc + "\n" +  
                    rscd + "\n" +  
                    rsce + "\n" +  
                    rscl + "\n" +  
                    rsct;

            String signature = generateSasSignature(storageKey, stringToSign);

            try{
            
            String sasToken = 
                    "sv="+signedVersion +
                    "&sr="+signedResource +
                    "&sp="+signedPermissions +
                    "&st="+ URLEncoder.encode(startTimeString, "UTF-8") +
                    "&se="+ URLEncoder.encode(expiryTimeString, "UTF-8") +
                    "&spr="+protocol+
                    "&sig="+ URLEncoder.encode(signature,"UTF-8")+
                    "&rscc="+ URLEncoder.encode(rscc,"UTF-8")+
                    "&rscd="+ URLEncoder.encode(rscd,"UTF-8")+
                    "&rsce="+ URLEncoder.encode(rsce,"UTF-8")+
                    "&rscl="+ URLEncoder.encode(rscl,"UTF-8")+
                    "&rsct="+ URLEncoder.encode(rsct,"UTF-8");
            
            String sasUrl = resourceUrl+"?"+sasToken;    
            System.out.println(resourceUrl+"?"+sasToken);
            String URL = "url";
         // Set the message body to the string you want to pass
            outMessage.getRootElement().createElementAsLastChild(MbElement.TYPE_NAME_VALUE, URL, sasUrl);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        //}
            // End of user code
            // ----------------------------------------------------------
        } catch (MbException e) {
            // Re-throw to allow Broker handling of MbException
            throw e;
        } catch (RuntimeException e) {
            // Re-throw to allow Broker handling of RuntimeException
            throw e;
        } catch (Exception e) {
            // Consider replacing Exception with type(s) thrown by user code
            // Example handling ensures all exceptions are re-thrown to be handled in the flow
            throw new MbUserException(this, "evaluate()", "", "", e.toString(), null);
        }
        // The following should only be changed
        // if not propagating message to the 'out' terminal
        out.propagate(outAssembly);
    }
        
    
    public static String generateSasSignature(String key, String stringToSign) {
        SecretKeySpec secret_key = new SecretKeySpec(Base64.getDecoder().decode(key), "HmacSHA256");
        Encoder encoder = Base64.getEncoder();
        String signature = null;
        Mac sha256_HMAC = null;

        try {
        sha256_HMAC = Mac.getInstance("HmacSHA256");
        sha256_HMAC.init(secret_key);
        signature = new String(encoder.encode(sha256_HMAC.doFinal(stringToSign.getBytes("UTF-8"))));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return signature;
    }   
}
Chris_dev
  • 17
  • 5

1 Answers1

0

The reason you are seeing this behavior is because you are creating an Account SAS which is valid for all blobs in your storage account.

What you need to do is create a Service SAS for a particular blob. Once you do that, you will only use the SAS URL for that blob only.

Gaurav Mantri
  • 128,066
  • 12
  • 206
  • 241
  • Thank you. How do I construct the service SAS URL ? – Chris_dev Mar 02 '23 at 18:05
  • Are you using any Storage SDK? – Gaurav Mantri Mar 03 '23 at 01:59
  • No, I am not using Azure SDK and I can't. I trying to achieve this in eclipse/Java and using Java just to the signature for SAS. – Chris_dev Mar 03 '23 at 14:18
  • Please edit your question and include the code you’ve written for that. Thanks. – Gaurav Mantri Mar 03 '23 at 14:31
  • I have modified the question and added to code – Chris_dev Mar 03 '23 at 15:40
  • I have also added canonicalizedResource. Yet fails with `Signature did not match. String to sign used was r b o 2023-03-03T17:30:05Z 2023-03-03T18:30:05Z https 2017-07-29` `String canonicalizedResource = "/"+fileName+"/"+accountName+"/"+containerName;` – Chris_dev Mar 03 '23 at 17:32
  • I see a new error after updating the stringToSign as below ` String stringToSign = signedPermissions + "\n" + startTimeString + "\n" + expiryTimeString + "\n" + signedVersion + "\n" + signedResource + "\n" + canonicalizedResource + "\n"+ protocol + "\n";`` `Signature did not match. String to sign used was rwd 2023-03-03T17:42:21Z 2023-03-03T18:42:21Z /blob/account/container https 2015-04-05 ` – Chris_dev Mar 03 '23 at 17:47
  • can you please help me in creating a SAS for a specific blob in java ? – Chris_dev Mar 03 '23 at 20:03
  • Sorry....Just saw the comments. Can you please edit you question and include the last code you used (based on your last comments) and I will take a look. Also, please check this for creating the string to sign - https://learn.microsoft.com/en-us/rest/api/storageservices/create-service-sas#version-2015-04-05-and-later. – Gaurav Mantri Mar 04 '23 at 02:13
  • Hello Gaurav, updated my original post and included full code. Like you said I also looked at the link you have provided for StringToSign that didn't work too. It failed with ``Signature did not match. String to sign used was r`` – Chris_dev Mar 06 '23 at 01:24
  • This how URL is looking. `https://accountName.blob.core.windows.net/container/File.txt?sv=2015-04-05&sr=o&sp=r&st=2023-03-06T01%3A40%3A02Z&se=2023-03-06T02%3A40%3A02Z&spr=https&sig=w0UO1XBSk1%2FPsF7ezE5cSg%2F5ODjpNDuRNN9AzgLsOSc%3D&rscc=&rscd=&rsce=&rscl=&rsct=binary` – Chris_dev Mar 06 '23 at 01:42
  • I believe the issue is with `"&sr="+signedResource +` in your code. Since you are generating a SAS token for a blob, the value of your `signedResource` variable should be `b` instead of `c`. Can you please try by changing that? – Gaurav Mantri Mar 06 '23 at 03:22
  • Hey Gaurav. I got this working after changing sr=b. You're best. Thank you. – Chris_dev Mar 06 '23 at 14:08
  • Hello Gaurav, can we convert the uploaded CSV file to excel format through Azure storage. ? – Chris_dev Mar 07 '23 at 22:25