Redirect only from certain website - c#

I'm working on a .NET Framework website that is only opened from a redirect command. Is it possible to do that only if I redirect from a certain website?
For example, if I have a personal blog and I want to redirect users to a certain site, that site would only open if the previous website is one I can whitelist or something like that.
If possible, I'd like to do it server side (the redirecting application is built in .NET Core 2.1)
Thanks a lot!

Technically, no. While you can use the Referer (historically mispelled) header, that header is not guaranteed to be present and can also be spoofed. In other words, if the client simply doesn't send the header, there's no way to know whether the user was redirected from your other site or not. Even if it is present, the client could have simply sent the header manually and completely bypassed your other site.
If the two sites are on the same domain or subdomains of the same domain, you can set a cookie at your other site that is then checked on the redirected site. However, the sites need to be able share cookies, which again, means same domain and both have data protections providers configured to utilize the same distributed store.
If you want to limit access the best and most fool-proof way is always going to be auth. Make them login at both points and you can ensure that no one can do anything you don't want them to do.

Related

How can multiple web apps be able to jointly use the same data from an identity database?

The question is really that how can an auth server that serves JWT be used by multiple websites of same company or domain (with the websites as sub-domains), for example? Not something for the public.
Already, I'm thinking of asymmetric JWT. Also, I don't want to implement OAuth 2.0 in order to avoid complexity and because the auth server would only serve web apps that are sub-domains of a same root domain.
seeking for less complex solutions based on the current description in this post
If you want a reliable and secure way to share resources between different sites, you might want to look at IdentityServer.
In a nutshell, you basically redirect anonymous user to identity server to login. After successful login, it will return a token to the user. Then the user uses that token to access resources from different sites.
Look at the basic workflow and screenshots at my GitHub sample project.
Ok so here is the deal.
Can multiple web apps access the same database (identity db or otherwise)? Of course! Now if you are using Entity Framework (and I assume you are though it wasn't stated) then this can get tricky as far as migrations etc. Personally I use Dapper so I never have to worry about that :-)
Yes the apps can each access the db but that is WAY different from from SingleSignOn which is really what you are talking about. You want a user to log in to one site and that identity to persist to other completely different sites. That's not nearly as simple as simply accessing a db. IdentityServer is virtually the standard for this kind of thing for many reasons.
No, the ajax approach will not work because when the user logs in at site1 the cookies are for site1. If he goes to site2 the browser does not have any cookies associated with site2 even though you sent credentials via ajax. The user was on site1 when this all happened so all cookies are site1 cookies, totally separate from site2 cookies. Even if you can find a way to make this work it would pose a serious security risk.
You could conceivably do something like this using hidden IFrames instead of ajax because you can set the iframe's site's cookies while you are there. But I don't recommend you do this as there are security risks involved.
You need to separate the idea of "Authentication" from the ideas of "Authorization" and even "User Management".
Authentication---- Am I who I say I am? (check my usename and password and maybe even additional form like text message etc)
Authorization---- Ok you know who I am, but what can I do on your site? This can vary from site to site. Maybe I am an admin on one of your sites but just a regular user on another. My individual site cookies will includes roles etc and they are different for each site.
User Management---- Can I change my name/email/etc?
The best way to handle this is to use a separate server app running IdentityServer. This handles the authentication and builds out the cookies for all of your sites at once. Ideally you should also use this for any user management but that can be a pain and isn't as vital. Here are a few sample apps for IdentityServer4.
Response to your Update 2----
Not exactly... Here is the basic flow: User goes to site1 and clicks "login". This fires a "challenge" which redirects them to website-auth. On website-auth the use submits their credentials (username/pw) via form post. This logs them in to the website-auth but then also redirects the user back to the original calling app (site1 in this case) with everything they need. Let's say the user now goes to site2, they are already logged in!!! Using IdentityServer4, the user will become logged in to all of the sites sorta automatically. You won't have to do extra stuff they way you described, just plug in the necessary stuff and let IdentityServer4 handle the rest.
Look, I understand that IdentityServer4 probably looks a bit intimidating, it did to me until I began working with it. Truth is, all of the hard stuff is handled for you. There is still a decent amount of configuration involved in getting it set up but it really is the best solution for what you are looking for.
Check out these quickstarts: https://github.com/IdentityServer/IdentityServer4.Samples/tree/release/Quickstarts
Response to Update3------
I understand the concern of relying on a third party and how that can seem like a questionable practice, especially when it comes to security. My response is this:
These guys are the EXPERTS in the field. So much so that IdentityServer has become the defacto security solution even in the basic templates Macrosoft provides.
Any home grown solution you will come up with will have more security holes that what IdentityServer has. This is not a slight on you at all. These guys know what they are doing. They have been doing it for years.
Why reinvent the wheel? You will spend 10x (at least) as many man-hours trying to come up with an alternative that, in the end, will still not be as good.
If what you were doing was a single website cookie based authentication then using identity really isn't necessary. Identity can do that, but there are other simple alternatives. But when it comes to multiple sites and SSO, and I really can't emphasize this enough, IdentityServer is the way to go.
The answer is a microservices auth serve that generates RSA/Asymmetric JWTs with a private key and the other servers each have the same counterpart public key to validate the JWT and retrieve the user claims.
But that solution doesn't not cater to the situation where each of those other servers need a different set of claims about about a user.
It is also not a single sign-on approach. So, I'll be back.
But OAuth 2.0 seems to be the answer, but it is too complex for my liking.

View authorization with angular and UI-Router considerations

First, my client side code is pure HTML, JavaScript, and angular.js. My server side API uses the Asp.Net Web API controllers.
Working off this similar example I am weary about passing user role information to the client. I am also weary about storing permission for views in my route configurations. My server side controllers and methods are built to inspect the incoming requests and authorize the specific user.
Should I worry too much about the client permissions if my server side will only allow authorized calls to be made? For example, let's assume a user and any admin can view that specific user's profile. If someone other than the user or admin tries to navigate to that profile the data will not be presented. An error from the server will be generated. The client side code can redirect the user if they are unauthorized.
I am curious to know what other developers have done for this type of scenario.
It primarily depends on your application specification, or your own desires. Passing user role information to the client helps you enhance UX in numerous ways. In addition to that, due to role check on different part of the front end, in theory users will not be able to do any request to your API endpoint which will end with a server error due to unauthorized request.
Let's throw some examples:
You are having a link (in navigation bar let's say) to the administrative section of your app. You really don't want to expose that link to ordinary users, since they will eventually click on it. It will result with a unauthorized response from the server, and subsequently got redirected to the previous page. - In my oppinion that is completely unnecessary
You have some edit form which can be editable both by users and admins. However, admins have few more fields to edit which are not permitted to the users. You really want to hide those fields, to prevent uneccesary unauthorized response from the server if those field were edited by ordinary user.
You need to "fine grain" your permissions to the user's page. So you don't really don't want to show a link to details of that user if your role doesn't allow you.
If you have stored roles in your client app, as a end user you won't need to the a server roundtrip in order to find out that you really aren't authorized to see something. Of course, you still must have server side authorization.
Keep in mind those scenarios are purely to give you example of few scenarios in which you will have a great benefit of having roles on your client side as well.

Handling security in an ASP MVC application that uses JS to a REST API

I have an ASP MVC4 web site. Originally, most of the content was served via controllers as one would expect. I have moved the data storage from SQL Server to MongoDB. I have also added a lot of ajax to update data client side, without a full refresh. This is working fine, but my controllers now have lots of methods that take json and return json. I was able to build a Node.js server that hits the database and exposes exactly the same functionality, without lots of going to and from C#.
My javascript client-side is now calling a Node.js REST API, this works great. My 'secure' code (like adding a new user) hits the same REST API from the server side.
My question is this: How can I handle security properly with this? I have three scenarios:
GET api/messages: No need for security, I want to expose my site's messages to anyone who is interested via a Json REST API.
GET api/my/messages: I need to allow access to this only if the user is logged in (it gets the user's messages).
POST api/users: This is a function that should only be called from the server, and nothing else should be able to use it.
As the user is already logging in to my ASP website, how can I use their logged in credentials to authenticate them with my REST service? While the user is logged in, the pages client side will hit it regularly for updates.
Is there any sensible/standard way to do this? The core idea is that the client side code uses a REST API that is at least partially open to the public, and that in fact that API offers all of my business logic - only parts of it (like creating a user) are locked down to super-admins only.
Thanks in advance!
Create two authentication middleware handlers. One you add to all your "my" routes and another which you add to your POST routes.
The "my" authenticator takes the asp.net auth cookie that is present in the request and makes a http call to your asp.net mvc site with it.
You'll need an action which either returns a 401 if the cookie is invalid otherwise it returns some info about that user's permissions perhaps.
If the request into node doesn't have a cookie, return a 401 again.
In addition, to prevent excessive calls to your mvc site to check the cookie, you could use the cookiesession middleware to set a cookie on the client with a flag of authenticated. That will result in 2 cookies for your client, but that shouldn't be an issue. Just make the node one expire before the aspx one.
The POST authenticator middleware can use any shared secret you like between your node and mvc server. e.g. a special header in the request.
If the user is required to login you can use [Authorize] on your controller actions. Autorization will be handled like any other webrequest.
Furthermore you might consider to add a key to your api requests which you can provide in the initial page load. A autorized user will have a GUID which he will sent with the api call. You can check if this key was issued by your app to a valid user.
As you said all the secure calls already go through your MVC server code which in turn calls the Node.js code, am I right? Basically you need a way to block calls to this Node.js from other clients that are not your MVC code.
Thinking out loud, these are the ideas that pop into my mind:
Use SSL only between MVC and Node. You can set up client and server certificates so that the Node code will only respond after authentication (I don't know how Node handles SSL so you will need some documentation here
If you want, the Node server could also check the call origin and so you can filter based on IP and only allow IPs where your MVC code is sitting
Use an encrypted authentication token on the secure methods on the Node code. Again I'm not really a Node expert but I can imagine it has ways of decrypting a token, or you can simply base it on a random number with a common seed... If noone has access to your server code ideally noone should be able to guess this token. Again, SSL will help against traffic sniffing
I am quite sure that people will come up with other ideas. For me, the most basic thing is anyway ensure that the secure methods are only accessible through an SSL connection and on this connection you can exchange all the info (token, passwords, etc.) you desire.

Programmatically login to a website and redirect the user to the logged in page?

Right now, I have all the employees of my company login to an external website using the company id, username and a password. We are trying to integrate it into an intranet portal which should provide seamless access to this website without requiring the user to enter these credentials.
Is there any way of doing this programmatically (.NET C#)? Very similar to screenscraping, Can I simulate the appropriate POST action and then redirect the user to the logged in page?
Any help is appreciated.
Thanks.
You can make a <form> in your page that mirrors the external site's login form with the same action= attribute, then fill put and submit it using Javascript.
Note that this requires that you send the user's password to the browser, which is never a good idea.
You can certainly post to the external website, the tricky bit will come when you redirect the user there, because there'll be cookies restrictions I think.
You might be able to do something with Javascript that makes the Client browser post directly to the third party with the correct credentials, look into jQuery's Post command.
Assuming that the external website maintains sessions with cookies in some way, the problem is, your company website can't set a cookie, except from it's own domain, and the 3rd party website can't read cookies except from it's own domain, so you can't transfer or pass the cookie across to your users.
The name for this technique is Single Sign-On. There's no one way to do it, but the emerging standard is called SAML. This requires participation on both parts (the originator and target website), so it's probably beyond your current purview.
Like the other two answers have mentioned here, you can post a formatted request directly to the action of the login script, but I can tell you from experience that that solution will be brittle, that is, it will shatter the second the target website makes any changes.
Your best bet is to contact the administrator of the target website and ask if they have an SSO (Single Sign On) solution.

Is it possible to have a personalized ASP.NET web app with only some SSL pages?

I have a web application that once signed in, personalizes almost all pages.
I want to be able to have some very specific pages locked down with SSL that may have sensitive information. From what I have been able to find, once you sign in via an SSL sign in page (area of the web site), the session information which I use to store a lot of personalization and user credentials is not available to the non SSL portion of the web site since they are considered 2 seperate applications.
This MSDN document pretty much says what I am talking about: MSDN Doc
Note: If you use this type of site structure, your application must not rely on the user's identity on the non-SSL pages. In the preceding configuration, no forms authentication ticket is sent for requests for non-SSL pages. As a result, the user is considered anonymous. This has implications for related features, such as personalization, that require the user name.
I am also not using forms authentication. When a user signs in a session object is made storing their credentials including their IP. If this session object exists for a particular user with the same IP then they are considered 'signed in' and the personalization features are enabled.
So my question is, are there any work arounds to this so that say my sign in page and some other page are using SSL, the reset of the site is not, and all pages have access to the same session variables?
If not can anyone suggest any other methods of accomplishing the same type of personalization features?
Since there are no comments, I thought I'd offer an inelegent but practical solution.
Leave the RequireHTTPS off in your forms authentication configuration block.
Next, you create a custom class that implements IHttpModule. This interface has an Init method that takes a HTTPApplication instance as an argument. You can then attach to the "AuthenticateRequest" event on this instance.
From here, you can 302-redirect any requests that come in without SSL when they should do. You'd probably want to drive which pages require SSL from a custom configuration section in your web.config.
To use this class for your requests, you have to add a line to the HttpModules section of the web.config.
For a start, have a look at this code project article: http://www.codeproject.com/KB/web-security/WebPageSecurity_v2.aspx - this will enable you to "step on" and "step off" of https for certain pages.
With regard to your session issues, I think you're a bit stuck. The standard forms authentication mechanism stores a cookie to identify the authenticated session which is available over http or https. My advice would be to switch to using forms authentication, and use the ProviderUserKey guid as the key for accessing your per-session data.
Hope this helps.
We have decided to not go with SSL in those few pages that required them. We looked at other web applications that did similar things and they do not use SSL. We are not really protecting anything that would be all that useful for a malicious user to go through the trouble of stealing anyways.
One option I did consider before the decision was made to remove the SSL was to store a user's session on the application's web service interface. Every page call would access the web service to access the session information. This would be enforced on every page call to ensure the session stayed active. I didn't do too much investigation into using this solution before the SSL decision was made so there could be many draw backs to this solution, especially having to make extra calls to the web service with every server hit.

Categories

Resources