how to submit a password with special characters from app to a web-server by NSURLConnection
Asked Answered
A

1

1

I have to login with my to a web-server.All works fine, but not generated passwords like |%<">{}¥^~ . How I have to encode passwords like this?

I create a User with password=|%<">{}¥^~ doset work ( for example a password like "user1234" works fine)

NSString *userName = self.usernameOutlet.text;
NSString *userPassword = self.passwordOutlet.text;
NSString *escapedString = [self.passwordOutlet.text stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
userPassword = escapedString;
NSString *post = [NSString stringWithFormat:@"login=%@&password=%@",userName,userPassword];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:@"%lu",(unsigned long)[postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:@"http://XXXXXXXX/login"]];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];

with passwords like "user1234" I get a cookie

with passwords like "|%<">{}¥^~" I get no cookie

what am I doing wrong?

Akvavit answered 18/2, 2019 at 6:31 Comment(6)
but I did it. see code NSString *escapedString = [self.passwordOutlet.text stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]; userPassword = escapedString;Akvavit
looks like the wrong character set. It should be URLQueryAllowedCharacterSetSlope
No, NSURLQueryAllowedCharacterSet won’t quite work either. It will let & and + pass unescaped (because those are technically allowed in the “query” portion of a URL, but not in a value (or key) of a x-www-form-urlencoded payload).Catling
the escapedString is "%7C%25%3C%22%3E%7B%7D%C2%A5%5E~" with URLHostAllowedCharacterSet and same with URLQueryAllowedCharacterSetAkvavit
@Akvavit Try password of "foo+bar&baz". It won’t escape the + or the &.Catling
As an aside, NSURLConnection is now deprecated. We’d generally use NSURLSession nowadays...Catling
C
1

It’s tempting to want to use URLQueryAllowedCharacterSet, but that won’t work for all strings. Notably & and + will pass unescaped.

If you’re wondering why we must percent escape & and +, too, it’s because these two characters have a special meaning in x-www-form-urlencoded requests. The & is used to delimit key-value pairs in a x-www-form-urlencoded request, so it will truncate your password. And most web services translate a + to a space, so you’ll want to percent escape that, too.

So, let’s first define a character set that will work:

// NSCharacterSet+URLQueryValueAllowed.h

@interface NSCharacterSet (URLQueryValueAllowed)

@property (class, readonly, copy) NSCharacterSet *URLQueryValueAllowedCharacterSet;

@end

and

// NSCharacterSet+URLQueryValueAllowed.m

@implementation NSCharacterSet (URLQueryValueAllowed)

+ (NSCharacterSet *)URLQueryValueAllowedCharacterSet {
    static dispatch_once_t onceToken;
    static NSCharacterSet *queryValueAllowed;
    dispatch_once(&onceToken, ^{
        NSMutableCharacterSet *allowed = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
        NSString *generalDelimitersToEncode = @":#[]@";   // does not include "?" or "/" due to RFC 3986 - Section 3.4
        NSString *subDelimitersToEncode = @"!$&'()*+,;=";

        [allowed removeCharactersInString:generalDelimitersToEncode];
        [allowed removeCharactersInString:subDelimitersToEncode];

        queryValueAllowed = [allowed copy];
    });
    return queryValueAllowed;
}

@end

Then, to make life easier for us, let’s define NSDictionary category for percent encoding a dictionary:

// NSDictionary+PercentEncoded.h

@interface NSDictionary (PercentEncoded)
- (NSString *)percentEncodedString;
- (NSData *)percentEncodedData;
@end

and

// NSDictionary+PercentEncoded.m

@implementation NSDictionary (PercentEncoded)
- (NSString *)percentEncodedString {
    NSMutableArray<NSString *> *results = [NSMutableArray array];
    NSCharacterSet *allowed = [NSCharacterSet URLQueryValueAllowedCharacterSet];

    for (NSString *key in self.allKeys) {
        NSString *encodedKey = [key stringByAddingPercentEncodingWithAllowedCharacters:allowed];
        NSString *value = [[self objectForKey:key] description];
        NSString *encodedValue = [value stringByAddingPercentEncodingWithAllowedCharacters:allowed];
        [results addObject:[NSString stringWithFormat:@"%@=%@", encodedKey, encodedValue]];
    }
    return [results componentsJoinedByString:@"&"];
}

- (NSData *)percentEncodedData {
    return [[self percentEncodedString] dataUsingEncoding:NSUTF8StringEncoding];
}
@end

Then, your application code can do:

NSDictionary *dictionary = @{@"login": userName, @"password": userPassword};
NSData *body = [dictionary percentEncodedData];
Catling answered 18/2, 2019 at 7:20 Comment(3)
thank you very much for your help. but it still doesn't work. I used the Password: |%<>{}¥^~ the server I try to login is no secret. dailygammon.comAkvavit
What is the URL for your endpoint that you’re connecting to? I don’t see docs for their API endpoints. Without seeing more, it’s hard to comment. The character that concerns me is the ¥, which is not an ASCII character and translates to two byte sequence. I also wonder about whether this endpoint that you’re connecting to is doing the right escaping/encoding of the strings you pass. E.g. % sometimes has a special meaning in some SQL interfaces. I’d suggest you try %foo and ¥foo and ..., once for each characters, until you figure out which is the problem.Catling
thank you for the hint to figure out wich character the problem is All characters |%<>{}"^~ work fine, only ¥ doesn't workAkvavit

© 2022 - 2024 — McMap. All rights reserved.