Even without SAS token in Azure I am able to open link - c#

I am storing pdf in my blob storage upon click of button. I thought of adding SAS tokens which I am able to add. I am doing something similar to 'GetBlobSasUri()' mentioned in https://learn.microsoft.com/en-us/azure/storage/blobs/storage-dotnet-shared-access-signature-part-2 and then I am saving that url. I am able to generate a SAS token and it is getting attached with the link I am saving in the blob. And after the token expires I am not able to open the url. But if I remove the SAS token which I added to the link, I am able to open the pdf document. I checked the access policy to make sure it is private. But it didn't help as in private mode I am able to open the pdf document by simply removing the SAS token.
And I am also wondering is it possible to add SAS token each time a PDF document opens. So that if one sends the url to somebody, that person will not be able to open the link once the token has expired. Right now what I have is on click of button a pdf is generated by storing it in blob and it has a SAS token appended to it.
I am also storing the token in my database along with the url to open pdf, does that make sense?
Can someone please suggest!

What is the container access level? Is it public or blob? It needs to be private if you don't want the URL (w/o the SAS token) to work.
Also, I agree with David; I wouldn't store the security token in your database. It should be generated as needed. You'll have to write something to generate it. It's not clear how you're serving the PDF Files to the user. To do what you're asking, you would need an app that would let the user select one, and then the app would give the user a URL with a SAS token on it that expires in a few minutes. There's no way that I know of for a PDF file to get a SAS token or generate a SAS Token on its own.

Although question is old, this will help someone looking for solution.
Please check access level for the file itself along with parent container. Setting this to private will make sure URL without token would not work. You should get ErrorCode, "ResourceNotFound".
Also, since this token is meant to be short lived, it should not be stored in Database and should be generated on-the-fly.
As a best security practice, tokens should not be stored in Database. You could store them in Azure KeyValult or similar.

Related

How can I register a new user with a user-defined unique identifier when leveraging OAuth code flow?

I'm building a sign-up / login flow for a web site. I plan to use Facebook as my identity provider instead of rolling my own.
I have a good feel for the server-side login flow with Facebook:
Call FB login API to get a code
Exchange the code for a user access token
Inspect the user access token
Validate the user access token details
After these steps, I'd like to check if the authenticated user is already registered in my system. If yes, simply return a newly generated bearer token, so the user can make subsequent requests to resource servers to access protected data.
If the user is not registered in the system, however, then I'd like to register them by creating a database entry. Before creating this entry though, I'd like to collect one piece of information from the user. Namely, I'd like for them to tell me their desired 'username'. I will use this unique username as my database primary key.
I'm not 100% sure on how to securely ask the user for their desired username before creating the database entry. This is my question. :)
One thought I had was to create a "redemption code". This code would be encrypted and contain the user initialization details, a secret only the server would know, and a timestamp. Something like this:
code: {
mySecret: "super-secret-value",
expirationDate: "date-value",
user: { ... },
}
After seeing the user is not in my system, I'd respond with the code + redirect the client to a page where they'd be able to specify their username. Upon submitting their username + code back up to the server, I could decrypt the code, and validate mySecret to determine the code is not tampered. If all is good, create the user in the database with the user information from the redeemed code. Lastly, I'd generate a new bearer token for the user and send it to the client.
Questions
Is my proposed redemption code strategy a secure way of requesting a username before creating the backend DB entry?
If not, what would be?
If yes, what is a secure encryption/decryption routine to use for this purpose in C#?
Flow Sequence
Steps 1-4 from above correspond to "Login" through "Validate" arrows.
My proposed redemption code strategy corresponds to the purple arrows.
Red text corresponds to Facebook specific nomenclature.
Note, Stack Overflow does something very similar to what I want to do. Before creating your account on SO, it will ask you for your desired Display Name (this happens after authenticating via Facebook, Google, etc.). After submitting your display name, your account is registered.
Use open source IdentityServer3.
Whatever flow you choose its already standardized in their server. Including (if you want or need) OpenID, OAuth2 etc.

Sign in to OneDrive without typing user informations

I need help to obtain an authorize code, is there any way to get one without accepting anything or any window that pops up. I need this for my service as an automated process.
I tried like a thousand ways but nothing works.
Please does anyone know a solution?
As per the docs (http://msdn.microsoft.com/en-us/library/dn659750.aspx), you can use a refresh token if your app has offline access in its scope.
If offline access is set, when you retrieve your authentication token normally, you'll also get a refresh token. When the normal token expires, you can request a new one similarly to the first token, replacing the code query parameter with the refresh_token parameter.
To be clear, the process looks like this as per the docs:
Send your user to your web service
Direct them to the OneDrive authorise page with the correct parameters (make sure offline access is in the scope)
Wait for them to be redirected back to your app with the authorisation code
Exchange the authorisation code with OneDrive (using the oauth20_token.srf endpoint) to receive a set of tokens (one of these will be refresh)
Wait for the access_token you received to expire
Exchange the refresh_token you received for a new access token as per the "Getting a new access token or refresh token" section of the docs

Cloudfront signed URLs using c#

I have tried a lot of things and I admit defeat (I have read a lot of responses on here but none have helped me so far). I am trying to setup signed URLs for files held on Cloudfont. I am able to create signed URLs for S3 but I cannot get anything to work for Cloudfront. For cloudfront I am using the following from the AWS SDK:
var url = AmazonCloudFrontUrlSigner.GetCannedSignedURL( AmazonCloudFrontUrlSigner.Protocol.http, "cdn.coffeebreakgrooves.com", privateKey,
file, cloudFrontKeyPairID, DateTime.Now.AddDays(2));
I get a signed URL generated but I get access denied when following the link, which when I read about it suggested I setup Origin Access Identity. So I then went to my distribution settings and setup Origin Access Identity and chose:
Restrict Bucket Access: Yes
Origin Access Identity: Use an Existing Identity
Grant Read Permissions: Yes, Update Bucket Policy
Then all files become publicly available on Cloudfront, regardless of any settings I have for ACL in S3 (so even if file.txt has no permissions for anyone in S3 it can then be accessed via Cloudfront) and I can't tell if the signed URLs work or not because the download works with or without the querystring and the files have become publicly available. Essentially, how can I make my files private but downloadable with a signed URL (and is my signing method correct?). If I delete the generated bucket policy access is restricted again. I think I need to know how to set the bucket policy so that the origin access identity can only access the bucket with a signed URL... maybe.
Many thanks in advance for any help!
After a bit of a break and a rethink here is where I was going wrong. It isn't possible to have some content secured and other not secured in the same distribution. Either a whole distribution is secured or not. Here is my solution.
Setup a new bucket for your secure items in AWS
Add a new distribution in Cloudfront pointing to the new bucket created in 1 and choose Yes for 'Restrict Viewer Access' and 'Yes' for 'Forward Query Strings' (this is only to add the ability to add content disposition to specific downloads) and choose 'Self' for 'Trusted Signers'
At the top of AWS click on your name and choose 'Security Credentials' and choose 'Continue' as we chose 'Self' above.
Click on 'CloudFront Key Pairs' and choose 'Create New Key Pair'. Download the key files when offered (they won't be offered again), you need the private key. Also copy the Access Key ID as you'll need that.
Go to your distributions, click on the i next to the secure distribution, click on the origins tab, click 'create origin' or select the origin and choose Edit then choose 'Yes' for Restrict Bucket Access, Create a New Identity and Yes Update Bucket Policy. This essentially means that Cloudfront can authenticate against your bucket.
In your project go to NuGet and search for 'AWS' and install the AWS SDK.
Copy the private key file (pk***.pem) to a folder above your website root (or somewhere relatively private)
Add some code as per the following to generate a secure URL with a Content Disposition header.
I have to say that I couldn't have solved this without the help of Torsten's post on https://forums.aws.amazon.com/thread.jspa?messageID=421768 which is in PHP but pointed me in the right direction:
string cloudFrontKeyPairID = "myaccesskeyidfrompoint4";
string pathtokey = HttpContext.Current.Request.MapPath("~/").Replace("wwwroot", "ssl") + "pk-mykeyidfilenamesavedin4.pem";
FileInfo privateKey = new FileInfo(pathtokey);
string file = "folder/mytrack.mp3?response-content-disposition=" +
HttpContext.Current.Server.UrlEncode("attachment;filename='a_filename_with_no_spaces.mp3'");
//I can't figure out how to do spaces or odd characters.
url = AmazonCloudFrontUrlSigner.GetCannedSignedURL(
AmazonCloudFrontUrlSigner.Protocol.http,
"customcname.mydomain.com",
privateKey,
file,
cloudFrontKeyPairID,
DateTime.Now.AddDays(2));
I hope that helps someone, I will be using this as a personal resource anyway! Enabling the Origin Access Identity on an existing bucket which doesn't have 'Restrict Viewer Access' set it essentially opens up permissions for all items on your bucket. This may or may not be desirable! If I have anything wrong please let me know, this is all pretty new to me.

Uploading to Amazon S3 without access & secret key

Usually when I upload to S3 storage, I use an AmazonS3Client like this:
var client = Amazon.AWSClientFactory.CreateAmazonS3Client(accessKey, secretKey, s3Config)
This works fine for internal use but now I am looking at providing an app to external users and don't want our (sacret) access & secret keys to be out there. I've set up an S3 bucket with a bucket policy allowing uploads (PutObject) from anonymous users but how do I use the Amazon SDK now? I can't seem to find any way without providing the access and secret key.
You should not open a bucket up for public write, likely. You are open to lots of attacks and will need to keep a close eye on your log files, etc.
A better solution would be to keep the default private access on the bucket, then create an IAM user who only has upload (and perhaps download) permissions for the required area. Then when someone wants to upload a file, you can use a call to your server which has the IAM keys to calculate and return a 'pre signed post' which will allow your client app to post a new file to the server. You can then use any auth tool you want on your server to decide whether or not to allow someone to upload, including no auth - but have abuse detection. When you do this the secret key for the IAM user is never sent down to the client, which may be in a debug session etc.
Since the whole post is pre signed, you can also decide where the file is allowed to go, the uploaded file name, etc and return that in the server response.
You just need to pass null for accessKey and secretKey and you can use the SDK for any anonymously allowed operation.
Check out this related question of mine it includes an official response from an Amazon employee from their developer forum! Relevant information from the linked question:
This is from an official Amazon employee on their forum:
As of the 1.3.8.0 release of the SDK you can pass null for the access
and secret key and the SDK will skip the signing process and try the
operations like GetObject as a public operation.
Norm

How to get NON-EXPIRING Page Login token with Facebook C# SDK?

I have exactly the same problem as Marco here: c# Facebook SDK, get token to write to my Page Wall , got to the same point as Marco (obtaining token manually and storing in web.config.
Problem I have is that this token is set to expire, so it cannot be really used as config value in my web application.
Is there a way in Facebook c# SDK to obtain this type of token?
Please note that as a page admin, I've already granted my FCBK app manage_pages permission (which does not seem to expire) so there should not be any human interaction necessary when obtaining this type of token.
Thanks, Antonin
EDIT
seems like running this request: https://www.facebook.com/dialog/oauth?client_id=<APP_ID>&redirect_uri=<URI>&scope=manage_pages,publish_stream,offline_access&response_type=token might be what I'm looking for, non-expiring access token. Pay special attention to values for scope parameter, especially offline_access.
I thought I had read somewhere that the page access tokens were temporary even when asking for offline_access. But that's really not an issue because you can use the user's permanent token to call me/accounts to get the list of apps and grab a token from there.

Categories

Resources