I am using HTTPS to a form-logon page.
When intercepting via
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge`
and extracting the Authentication Method used via
NSString *authenticationMethod = [[challenge protectionSpace] authenticationMethod];
I get the following
NSURLAuthenticationMethodServerTrust
But expected result should be
NSURLAuthenticationMethodHTMLForm
Is this due to using HTTPS?
Short answer: Yes
The purpose of the NSURLAuthenticationMethodServerTrust authentication method is that the client can verify and trust that the server is actual the server it pretends to be.
The NSURLAuthenticationMethodHTMLFormis used to authenticate a user via a web form. The server sends a web form and requests user credentials. This authentication does not require to be send over SSL/TLS. But then the user's credentials will be send in the clear, which is a bad thing from a security point of view.
Client authentication is also part of the TLS protocol. In this case, you may receive a challenge whose method is NSURLAuthenticationMethodClientCertificate.
Notice, you may receive more than one authentication challenges.
Related
I am aware of How to Respond to an Authentication Challengelike we have NTLM Authentication as there are 3 options.
Provide authentication credentials.
Attempt to continue without credentials.
Cancel the authentication request.
But just want to know the thoughts here, when we go with the first option Provide authentication credentials we pass the username and password URLCredential is there any possibility of leakage of credentials, is it secure to pass the credentials, what is happening behind the screens? how Apple network API sending the credentials to the server?
Yes, we can set the policies like server domain, failure count etc. but from the security point of view is it safe? from Man in Middle Attack (MIMA) or anything else?
Maybe the way I have posted my question is not clear but I was looking more from the Application credential security point of view with NTLM Authentication and after lots of Google, I have found, how’s NTLM works and it’s pretty interesting to see that client don’t share the password with the server. here are the steps as follow.
The client makes the request to the server.
The server needs to validate the user because there is no identity so server generates 16 bytes random number called as the challenge and sends it to the client.
Client hash this challenge with the user’s password and return it back to the server that is called the response it also includes username as plain text and challenge sent to the client.
The server sends everything to the domain controller and it uses the username to retrieve the hash of the user’s password from security account manager database and hash the challenge.
Domain controller shares the response back to the server if they are identical then authentication is successful otherwise a failure.
So the interesting part is here that Network API doesn’t share the password with the server it means it very secure.
I hope it will help others, For More.
There are multiple types of challenges, and the answer to your question depends on what type of challenge you're talking about. Each challenge has a protection space, which basically tells what type of challenge you're responding to.
To answer your question for the most common protection spaces:
Basic password-based authentication (NSURLAuthenticationMethodHTTPBasic): The credential you pass is sent in cleartext to the server (HTTP) or encrypted by the session key (HTTPS).
Digest authentication (NSURLAuthenticationMethodHTTPDigest): The credential you pass is cryptographically hashed with a nonce provided by the server, and only the resulting hashed token gets sent over the network.
NTLM authentication (NSURLAuthenticationMethodNTLM): The credential you pass is cryptographically hashed with a nonce sent by the server, and only the resulting hashed token gets sent over the network.
Client Certificate authentication (NSURLAuthenticationMethodClientCertificate): The certificate is sent to the server, but not the private key data. The client uses the private key to sign the prior TLS handshake data as a means of letting the server verify that the client really does have the private key associated with that cert.
Server certificate validation (NSURLAuthenticationMethodServerTrust): If you pass a certificate obtained from the server, you MUST validate it first, or else you effectively reduce the level of security to that of HTTP (i.e. any server can send any cert and you'll be saying to trust that cert when talking to the server).
The list above covers the most common protection spaces. Kerberos is its own animal, and I don't know anything at all about how that works. And there's also the "Form" protection space, which is just a placeholder for custom authentication that you can use in various parts of your app's code, but is not actually supported in any meaningful way.
It is worth noting that Basic, Digest, and NTLM authentication provide no protection against man-in-the-middle attacks if the attacker can alter data in transit, because the authentication token provided does not depend on the rest of the request in any way. Thus, these are really suitable only for use over an encrypted channel (HTTPS).
I'm using AFNetworking and associated goodies, and I've subclassed AFOAuth2Client to do some OAuth work with tokens and so forth.
For testing purposes, I'm working on a dev server that requires a username & password to access the pages/API endpoints. When I browse to one of the pages, I get a little dialog box, enter the credentials, and I'm good for some time. As I understand it this is "Basic Authentication" or "Basic Access Authentication".
So when I instantiate my AFOAuth2Client subclass, I use
[self setAuthorizationHeaderWithUsername:#"user" password:#"pass"];
with the appropriate username and password that I would type into my browser when prompted, but when I attempt to access the dev server, using the HTTPOperationWithRequest: method, I get rejected.
So instead, when I instantiate the client, I try:
NSURLCredential *credential = [NSURLCredential credentialWithUser:#"user" password:#"pass" persistence:NSURLCredentialPersistenceNone];
[self setDefaultCredential:credential];
And this works fine for all requests I make; the server lets me in.
Now as far as I understand, the first method is setting the Authorization: HTTP header with my credentials, and the second method tells my request that when it gets challenged, set the Authorization: HTTP header with my credentials...same thing, no?
Why would the first method fail and the second one succeed?
Is it possible for me to authenticate an iOS App without user interaction to the level where it can make Facebook requests for Page data?
For example, in an app for a musician, I would like to be able to make facebook requests for the musician's artist page including wall posts. I could then get the raw data for their page and style it however I please. This wouldn't require a user to log in and session authentication would be done asynchronously by the app itself, using embedded credentials.
I'd like to use the SDK but am thinking this would require manual OAuth Access Token requests and posts.
Thanks for the help!
UPDATE:
To clarify, I am curious about the possibility of the following:
1) App loads and makes a request for an OAuth Access Token using credentials baked into the App
2) App can then make requests to facebook for feed data from a predetermined page feed
3) None of this requires any user interaction or bounces the application to mobile safari, etc.
I dont really understand what you want, but it is possible to authenticate without user interaction:
If the request requires authentication in order to make the
connection, valid credentials must already be available in the
NSURLCredentialStorage, or must be provided as part of the requested
URL. If the credentials are not available or fail to authenticate, the
URL loading system responds by sending the NSURLProtocol subclass
handling the connection a
continueWithoutCredentialForAuthenticationChallenge: message.
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/AuthenticationChallenges.html#//apple_ref/doc/uid/TP40009507-SW1
There is a way for authentication:
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
Ok - I figured this out. Feel pretty silly that I didn't know you could do this.
You can request an access token for an app id & secret. This will allow you to make public data requests that require an access token.
TO REQUEST ACCESS TOKEN:
https://graph.facebook.com/oauth/access_token?grant_type=client_credentials&client_id=11111111&client_secret=9999999999
Then, simply use the returned Access Token in your Feed Request:
https://graph.facebook.com/musicpage/feed?access_token=ACCESS_TOKEN
If this is against TOS or deprecated - please let me know. For now this seems like the solution!
I have a client (on iOS) that connects to a server using a hard-coded https url.
When a connection is established the server may indicate that for future connections a different machine name and/or port should be used. In addition the server can specify url location suffixes to fetch data from.
i.e. the following URL might be hardcoded in the client:
https://machineName.address.port/url-suffix
and after a connection is established the sever could inform it to use machineName2 and portX and url-suffix /someLocation/somewhere, so the next time the client connects it will use the url
https://machineName2.address.portX/someLocation/somewhere.
The address part or the url cannot change.
At the moment the client has the following for the connection authentication challenge, i.e. it'll connect to anything:
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
SecTrustRef trust = challenge.protectionSpace.serverTrust;
NSURLCredential *cred;
cred = [NSURLCredential credentialForTrust:trust];
[challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
}
At the moment this app isn't doing anything that requires heavy security - there's no bank info being accessed, the user doesn't log onto anything, no user info is being transmitted. The client is just downloading data from the server onto the device.
Without adding certificate checking on the client side could a spoof server send porn to the device or something, or is the fact a https connection is made and the url address is hardcoded sufficient?
HTTPS provides data encryption and authentication, but your certificate should be signed by a certificate authority. Accessing a hardcoded URL is not a security flaw—that's how webservices/APIs work. However, without proper certificate setup someone could potentially impersonate your server. Just using SSL/TLS is not enough.
I am attempting to secure a website I am currently developing using ASP.NET MVC 2.0 and forms authentication. In order to secure the forms authentication cookie I want to set the requiresSSL property to true so the cookie is only send by browsers when the connection is under SSL, and obviously ensure that all resources which require authorization are under SSL.
My problem is that we are using Application Request Routing to fulfil a number of functions, one being SSL offloading, therefore by the time a request hits any web server in our farm the request is no longer under SSL and the FormsAuthentication.SetAuthCookie method fails because an SSL connection is required to set the cookie when requiresSSL is specified.
Anyone have any ideas as to a work around here!
Thanks
So I have a work around for this, however if anyone has any better ideas please feel free to comment. Essentially you need to intercept the response at the end of the request and manually set the Secure property on the forms authentication cookie, pretty obvious really, you will also need to set the requireSSL property in the forms authentication configuration to false. Also bear in mind we do not want to enable HTTPS for the entire site for authenticated users hence this work around.
There are a couple of caveats to this approach and a few things to be aware of.
I found during testing that the forms authentication cookie was always written to in the response, so I kept overwriting the valid authentication cookie in the browser with an empty authentication cookie, to get around this I included some logic in the HTTP module to work around this, see code snippet below.
All requests to the application which require authorization must be under SSL, otherwise the request will not contain the authentication cookie in order to authenticate the user.
Because you are only passing the authentication cookie for SSL requests you will need another mechanism to tell your application that the current user is authenticated when they browse the non SSL areas of the site, I have implemented this with an additional cookie which is set when the user logs in, and does not have an expiry date set, so will expire at the end of the users session, of course this cookie is removed if the user logs out.
Below is the logic implemented in an HTTP Module to affect the above, I have been testing this the last couple of hours and have not come across any problems yet, I will be sure to update this post if I do!
We should only ever send an authentication cookie to the client if the user has just logged in here's the logic
If the request has an auth cookie the user is already authenticated
and under SSL so ensure we do not send a new auth cookie in the
response.
If the request does not have an auth cookie but there is a valid
auth cookie in the response, set the response auth cookie to secure,
so it is only transmitted by the browser under SSL.
If the request does not have an auth cookie and the response has an
invalid or empty auth cookie, ensure we remove the response cookie
so we dont overwrite the valid cookie in the client browser.
private void EndRequest(object sender, EventArgs e)
{
var application = (HttpApplication)sender;
if (ValidRequest(application.Request) && application.Response.Cookies.Count > 0)
{
//only do the below if the user is not logging out the site, if the user is logging out we can
//leave the default forms authentication behaviour which is to expire the auth cookie
if (application.Request.AppRelativeCurrentExecutionFilePath != "~/authentication/logoff")
{
var requestAuthCookie = application.Request.Cookies[FormsAuthentication.FormsCookieName];
var responseAuthCookie = application.Response.Cookies[FormsAuthentication.FormsCookieName];
if (requestAuthCookie != null && responseAuthCookie != null && responseAuthCookie.Value.IsNullOrEmpty())
{
application.Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
}
else if (responseAuthCookie != null && !responseAuthCookie.Value.IsNullOrEmpty())
{
responseAuthCookie.Secure = true;
application.Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
application.Response.Cookies.Add(responseAuthCookie);
}
else if (responseAuthCookie == null || responseAuthCookie.Value.IsNullOrEmpty())
{
application.Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
}
}
}
}
SSL offload should allow you to make a SSL connection from the SSL offloader to the web server.
The SSL connection from the SSL Offloader to the web server should use the lightest and fastest (and probably weakest) encryption available.
This allows you to use secure cookies, reduce the encryption load on the servers and avoid the modification of your code.