I have coded a C# Web API application and some of the calls require the user to be logged in.
Here is my current code to log the user in:
[InitializeSimpleMembership]
public bool TestLogon(string userName, string password, bool rememberMe)
{
return WebSecurity.Login(userName, password, persistCookie: rememberMe);
}
My question is this:
How secure is the above call? Is the above code secure enough for a commercial application, and if not, how can the code be improved? Do I need to implement any sort of AntiForgeryToken?
Thanks in advance
please see my answers below.
1. How secure is the above call
Because, by default, the credentials are not encrypted, so if there isn't any encryption in place like SSL to protect communication, the data will not be secure. More details from here
2. Is the above code secure enough for a commercial application, and if not, how can the code be improved?
Like the other has suggested, you'de better to use Token-Based security, and enable SSL communication. This link is really useful
3. Do I need to implement any sort of AntiForgeryToken?
Yes, you will have to prevent cross site request forgery attacks.
Hope this help.
Related
I am building an API which will use authentication with Auth0 and will have web and mobile clients.
Both clients will get their tokens using web based login from Auth0.
I am looking for the best way to get and store some user information in my API database, so I can e.g. list users in some group, relate article with the author, give some permissions to the user which cannot be stored in Auth0 (for 2 reasons: no mtm tokens and more important, that it's sort of multi tenant app and permissions are to complex to keep them in tokens).
There is userId in the token which can be used but e.g. when to trigger user save/update? Running it on each and every request does not sound efficient.
Anyone has done something like this?
How to approach it in the best way?
I have figured out a solution, however if anyone here would recommend a better approach, please do! Thanks to comments I went into hooks and then rules direction, so I appreciate any engagement.
I see it as fairly simple case, a bit tricky during local development but can be worked around with some development middleware in the API.
I am going to use Auth0 rules with crazy simple rule:
function (user, context, callback) {
const axios = require('axios');
axios.post('https://my-web-api.com/auth0/notify', { user }, {
headers: {
'x-api-key': configuration.API_KEY
}})
.then(() => callback(null, user, context));
}
In the Rules, I have added API_KEY as a variable so it is not there in the code, encrypted, safe.
By using this I will send the current user profile from Auth0 to the backend where I will simply check if the user exists or not and update a profile if necessary.
As per docs:
Please note that rules also run during the token refresh flow.
it gives me also updates during the refreshing flow, so if anything changes, I will get the updates as well.
I'm building an saas application using asp web api 2 and asp identity. This api will be consumed by web, mobile and desktop applications. How do i make sure that all calls to my web api method is authorized? In web, we can ask user to login before going to certain page, but how bout mobile/desktop? Does user need to provide login and password on each call? Are there better solution for this? I've been searching and havent found any article about this. A sample or articles will be much appreciated.
Usually when using api's as a back-end you have to authenticate the user on every request.
(it actually also happens with other frameworks, such as mvc.net, but they keep track of the user using cookies which are send back and forth with every request)
I would suggest you use token based authentication (e.g. OAuth). In such a case you set the token in the header of the request. This token will be used to authenticate (and potentially authorize) the user.
If you need more info i can always explain it a bit more.
== Edit: Added Code sample ==
You could use a request handler to validate that the header of the request includes a valid token:
public class AuthorizationHeaderHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage pRequest, CancellationToken pCancellationToken)
{
IEnumerable<string> apiKeyHeaderValues = null;
if (!pRequest.Headers.TryGetValues("Authorization", out apiKeyHeaderValues)
|| !TokenRepo.IsVallidToken(apiKeyHeaderValues))
{
var response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent("{\"error\": \"invalid_token\"}")
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
return Task.Factory.StartNew(() => response);
}
return base.SendAsync(pRequest, pCancellationToken);
}
}
All you have to do is keep which token is associated with which user, and make sure tokens have an expiration period. Once this is passed, it is also not valid anymore.
I hope this clarifies it a bit.
Again, if you have more questions, do not hesitate to ask.
I'd like to use C# to authenticate a username and password through SMF (Simple Machines Forum). I was wondering if there is a secure way to send a username and password string through HTTPWebRequest that can be easily combined with SMF's authentication system, unless there is a better way (I do not want to use direct mySQL access).
What I am thinking of is something like, on the server side, check if the login is successful. If so, it will echo a certain string "true" and "false".
I've taken a look at the "verification hooks", but I'm not sure how to use them. I also took a look at the login scripts and saw that there's quite a bit of security behind it. Does SMF have any sort of API that can isolate just the login authentication and return a true/false?
Thanks.
There's a quasi RESTful API for SMF 2.x here:
http://www.simplemachines.org/community/index.php?topic=458832.0
One of the functions will validate your login for you. If you need to expand it to do other things it can easily be done.
I'm using the ASP.Net Login control to login a web application. When the user submits the form, I want to call a function to encrypt the password before ASP.Net sends the information for authentication.
I tried to add a Customer Validator on the password field and if the password is not empty, the Password.Text will be replaced with the encrypted value. However, it seems ASP.Net still sent the original password for authentication.
I also tried adding a onClick event on the login button to encrypt the password but ASP.Net still sent the original password for authentication.
Is there a way to do this? Thank you!
UPDATE:
I'm sorry for not making this clear. What I need is to encrypt the password at Server Side.
I'm not using ASP.Net Membership to encrypt or hash the password while registering a user. The passwordFormat property has been set to "Clear".
What I am doing is:
While a new user registers, I use a customized function to encrypt the password and save it to database.
When a user tries to login, I want to use the same function to encrypt the password entered by the user and let ASP.Net to authenticate the user.
The problem I'm having is I can't find a way to call the encrypt function before ASP.Net initiate the authentication process.
Hope this makes sense. Thank you.
Allen
You were definitely on the right track with adding the OnClick event. If you are trying to do the encryption client-side then you will need to use the OnClientClick event instead (OnClick happens server-side and OnClientClick happens client-side). I initially assumed you were using it to call a client-side javascript function that does the encryption?
[EDIT]
However, if you are doing the encryption server-side, and using a Login control, then you might want to use the OnAuthenticate event:
<asp:Login id="Login1" runat="server" OnAuthenticate="OnAuthenticate">
</asp:Login>
Then do your encryption here:
private void OnAuthenticate(object sender, AuthenticateEventArgs e) {
bool authenticated = false;
String encryptedPassword = Encrypt(Login1.Password);
authenticated = YourAuthenticationMethod(Login1.UserName, encryptedPassword );
e.Authenticated = authenticated;
}
private bool YourAuthenticationMethod(String username, String encryptedPassword) {
//test the encrypted password against that retrieved from your database using the username
}
Why are you trying to encrypt the password client side before sending it to the server? That's really no more secure than sending the server your plain password. The code you write to encrypt this password is viewable by anyone.
On the server you should use something like this:
public static string createPasswordHash(string pwd)
{
return FormsAuthentication.HashPasswordForStoringInConfigFile(pwd, "md5");
}
Sorry if I misunderstood something about the ASP.NET technology, but it should provide server side application. Therefore, You should not be able to use any "c# code" to encrypt transferring password. If You cannot use secured HTTP (if You could, You wouldn't need to encrypt the password, because all communication would be encrypted), JavaScript is "only way". However, if Your project contains client-side application (the one that is really installed (or run) on client's computer), You can use full c# potential of course.
There is a discussion why would You need it at all. As I see no better explanation, I will try to provide my own: The encryption of password transferred via Internet is essential if you expect that someone will listen to the communication in between client's computer and the server. As I understand it, if user clicks on the log-in button at your site, the page he sees the form on is actually downloaded in his computer and the click only causes a transfer of data from client to server. The data is not encrypted at all and any evil Eve can listen to the transfer obtaining client's plain text password.
But You should be aware that even if You send encrypted password, the encryption covers only plain text password problem. If Your server-side application expects password encrypted with a static algorithm and my only goal (as evil Eve) is to successfully log into the system, I don't actually need to know the password itself, its encrypted form will be good enough. It is quite complex problem and it depends on how much security Your connection really needs - if the costs (or Your effort) are relevant to the risk. If You are really serious with as best as possible security, You should go through some security standards.
The point about seeing Your algorithm written in JavaScript is irrelevant as far as it is well implemented (RSA is both open and easily accessible algorithm, though safe enough).
An application I'm modifying has a Web Service, and one of the web methods on that web methods is used to authenticate a user against active directory. So the current code called by the AuthenticateUser web method looks something like this:
string domainAndUsername = aDomain + #"\\" + username;
string ldsPath = buildLdsPath(searchBase);
DirectoryEntry entry = new DirectoryEntry(ldsPath, domainAndUsername,
password);
try
{
//Bind to the native AdsObject to force authentication.
object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(sAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
// more code to validate the result, etc...
}
When I started looking at this code, the first thing that worried me is the arguments to the web method look like this:
[WebMethod]
public ResultObj AddRole(string roleToAdd, string username, string password)
{
// code that calls above Authentication fragment...
}
So the current web service is expecting a password string, presumably sent in the clear over the network as XML, when the request is made to the service.asmx page.
Has anyone dealt with this type of issue before? Are there alternative Active Directory authentication mechanisms I could use that would avoid having to pass in a plain-text password? The best option I could come up with on my own is to invoke the WebMethod using an encrypted password, and have the code on the other side decrypt it. However, I'd prefer a better solution--e.g.: is there some way to do search for a DirectoryEntry using a one-way hash instead of a password?
Edit:
Additional Details: To this point I haven't considered SSL as this is a tool that is internal to our company, so it seems like overkill, and possibly problematic (it'll be running on a company intranet, and not externally visible). The only reason I'm even worried about the security of sending plain-text passwords is the escalating amount of (possibly password-sniffing) malware present even on company intranets these days.
If you have a public/private key combination, then the client could encrypt with the public key, and you decrypt with the private key.
However, that's too much work for the client, and not a very "web method" way of doing it.
Since you are sending the user name and password as parameters then you should resort to transport security, HTTPS, basically, which requires you to have a public/private key combination issued to you from a trusted certificate authority.
It should be noted that your association of SSL encrypted channel with an external facing site is incorrect. The point of wanting to encrypt a channel is to prevent man-in-the-middle attacks, exactly like you are trying to do here.
You could use a self-issued certificate, but that would require installing the public key of the certificate on each machine that is going to call your web method. It's easier to just get one from a trusted authority.
HTTPS (as mentioned) is the easy choice. Or, you could just let IIS handle authentication thru Digest or NTLM. Your app can still make authorization rules. NTLM is secure, but it'll hurt your interop. Otherwise, AD does offer some digest authentication methods, but I don't have tested code using them.
With Server 2000 domains, there's an option for "Store passwords in reversible format" - that will allow a domain controller to calculate MD5 hashes of the password to compare against your presented MD5 hash. MS realized this was a bit of a security problem, though, so Server 2003 implemented "Advanced" digest authentication - which precomputes the hash.
LDAP signon should select MD5 Digest as the authentication type, supply the username, and then supply the MD5 hash of the password. The normal LDAP clients will probably want to MD5 your password themselves though, so you'll have to override or craft them yourself.
We put our AD service on its own web site and got an SSL cert. Problem solved.
I think SSL, or possibly IPSec, are probably your best solutions.
For our particular situation, because both the client and the web service are running on our company Intranet, a solution that may work for us is to handle the Authentication on the client end using the Integrated Windows NTLM authentication, and then then just have the client supply the credentials to the Web Service. Here is the client code:
public void AddRole(string roleName)
{
webSvc.Credentials = CredentialCache.DefaultCredentials;
// Invoke the WebMethod
webSvc.AddRole(roleName);
}
The web method will now look like this:
[WebMethod]
public ResultObj AddRole(string roleToAdd)
{
IIdentity identity = Thread.CurrentPrincipal.Identity;
if (!identity.IsAuthenticated)
{
throw new UnauthorizedAccessException(
ConfigurationManager.AppSettings["NotAuthorizedErrorMsg"]);
}
// Remaining code to add role....
}
Again, I must stress this solution will probably only work if the server trusts the client, and both talk to the same Active Directory server. For public Web Services, one of the other answers given is going to be a better solution.
For further information, see:
Microsoft Support Article on passing credentials
MSDN Article on Building Secure Applications
MSDN Article on Windows Authentication - includes info on correctly configuring the web service to use the Windows Principal and Identity objects needed.