I recently noticed a new option when creating a certificate for a given iOS client.
The option is titled
Apple Push Notification Authentication Key (Sandbox & Production)
Get an authentication key to generate server-side tokens. You can use
these tokens as an alternative to certificates for your notification
requests.
One authentication key can be used for multiple apps and does not
expire.
How does one go about setting this up?
Apple Push Notification token-based authentication is an alternative to using provider certificates to connect to APNs. The provider API supports JSON Web Token (or JWT), an open standard, to pass authentication claims to APNs along with the push message.
To generate a provider token, obtain a private key for signing the
token as described in Creating a Universal Provider Tokenin App
Distribution Guide. You should construct a token with header
containing a 10 character Key ID (kid). The token claims portion
contains Issuer (iss) which is a 10 character Team ID. Your Team ID
and Key ID values can be obtained from your developer account. The
claims shall also contain Issued At (iat) which is the number of
seconds from Epoch in UTC when the token was generated. The token must
be signed with the Elliptic Curve Digital Signature Algorithm (ECDSA)
using the P-256 curve and the SHA-256 hash algorithm (ES256),
specified as a value in the algorithm key (alg).
{
"alg": "ES256",
"kid": "ABC123DEFG"
}
{
"iss": "DEF123GHIJ",
"iat": 1437179036
}
For additional information along with list of available libraries for generating signed JSON web tokens, refer to https://jwt.io
This is a swift library to sign your JSON Web Token (or JWT) : kylef/JSONWebToken.swift
Note: Only providers tokens signed with ES256 algorithm are supported
by APNs. Unsecured JWT or JWT signed with other algorithms will be
rejected with a response indicating an Invalid Provider Token.
SOURCE : APPLE : Provider Authentication Tokens
WWDC 2016 - Session 724 : Token Based Authentication
PS:
The biggest difference is that The Key Way will not be expired than Certificate will be expired after one year.
Related
I make use of the class org.springframework.security.jwt.JwtHelper from org.springframework.security:spring-security-jwt:1.1.0.RELEASE for decoding JWT tokens, e.g.
Jwt jwt = JwtHelper.decode(accessToken);
String claims = jwt.getClaims();
The above classes are deprecated and the deprecation comment points to Spring Security OAuth 2.0 Migration Guide.
This guide does not talk about any replacement for JwtHelper.
I found the class JwtDecoders which creates a JwtDecoder in the new spring-security-oauth2 project. But JwtDecoders requires an issuer to be passed.
Since I do not wish to verify the token, is there a simple alternative available? Otherwise I can split on . and base64-decode the token, and use any JSON library to parse.
The replacement used in Spring Security is nimbus-jose-jwt. If you don't use Spring Boot, you have to choose a version otherwise Spring Boot will choose one for you.
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
</dependency>
You can just use it like this:
import com.nimbusds.jwt.JWTParser;
....
JWT jwt = JWTParser.parse(accessToken)
Header = jwt.getHeader();
JWTClaimsSet jwtClaimSet = jwt.getJWTClaimsSet();
This worked fine for me without any new dependency
Jws<Claims> claimsJws = Jwts.parserBuilder().setSigningKey(Keys.hmacShaKeyFor("secretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecret".getBytes()))
.build().parseClaimsJws(token);
String username = claimsJws.getBody().getSubject();
Authentication authentication = new UsernamePasswordAuthenticationToken(username,null, null);
SecurityContextHolder.getContext().setAuthentication(authentication);
Do not skip token verification! Failure to verify the token properly will result in an insecure app.
It is very important that you check the issuer (iss claim) of the token and verify it is correct and that it is supposed to be accepted by your application. Only accept tokens from issuers that have the authority to grant access tokens for your app.
Also verify the token is intended for your app (check aud claim): you don't want users misusing tokens intended for other apps (e.g., if user has token with all the right claims, but with aud claim set to another app; that shouldn't be a valid token for you).
Now, make certain to check the signature of the token to verify it is actually signed by the issuer and it is not a bogus token: you can find the issuer's public keys by contacting the issuer. If you don't get the public key directly from the issuer, and you don't verify the signature of the incoming token properly, a malicious user will be able to forge a seemingly-valid token that your app will accept, and your app will be at risk of leaking catastrophic amounts of data.
The last step is to check validity (is it expired?) and to then to check for whatever other claims or scopes your app expects and requires.
If you wish to avoid an additional dependency (e.g. nimbus-jose-jwt), feel free to fork or copy this small utility class: JwtUtils.java
Trying to create apple developers push certificate for ECC algorithm as communication with APNS required ES256 alg as documented here.
NOTE: APNs supports only provider authentication tokens that are
signed with the ES256 algorithm. Unsecured JWTs, or JWTs signed with
other algorithms, are rejected, and your provider receives the
InvalidProviderToken (403) response.
Getting error below,
CSR algorithm/size incorrect. Expected: RSA(2048)
Any idea why?
Note: I have created proper ECC based signingcert from Keychain app.
I have changed stripe csr file extension from stripe.certSigningRequest to stripe.csr and Its working fine for me.
I have an application registered in Azure AD which uses certificates. I am trying to write a script which would add a new certificate to the application. This can be used to add a new certificate when the existing certificate is going to expire.
I am trying to use AddKey function of Azure AD Graph API. The request body of this api as a parameter 'proof' which is a JWT assertion signed by the existing certificate of the application. The doc says the "aud" claim in JWT should be set to "AAD Graph SPN". Here what is meant by "AAD Graph SPN"?
I tried with a JWT where "aud" was set to "00000002-0000-0000-c000-000000000000". But I am getting the following error,
{
"odata.error": {
"code":"Authorization_RequestDenied",
"message":{
"lang":"en",
"value":"Insufficient privileges to complete the operation."
}
}
}
Any thoughts on this?
I am getting the access token to call the Azure AD Graph API via "Resource Owner Credentials Grant" flow . To get the access token i am using the client_id "1950a258-227b-4e31-a9cf-717495945fc2" (The Well Known Client ID for Azure PowerShell")
My script (For deployment purpose) does something like below,
i) Get the access token as described above and registers a new application in Azure AD with a initial certificate.
ii) When the initial certificate is about to expire it should add a new certificate to the created application.
According to the documentation, you must use a self-signed JWT token to access that API:
As part of the request validation for this service action, a proof of
possession of an existing key is verified before the action can be
performed. The proof is represented by a self-signed JWT token. The
requesting application needs to generate a self-signed JWT token with
the following requirements...
The "Resource Owner Credentials Grant" won't work here in this situation. Instead, use the "Client Credentials Grant":
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service
The application you want to update should be the Client ID used to get this access token.
The other option is to update the application directly using an PATCH request on the Application Object:
https://msdn.microsoft.com/en-us/library/azure/ad/graph/api/entity-and-complex-type-reference#application-entity
Using this method, you should be able to update using the method you described above (user credentials and an external Client ID)
Let me know if this helps.
I'm currently developing server-side support for sending iOS push messages (the server's in Java if that's relevant). Apple developer documentation "Communicating with APNs" claims that one can either use a certificate or a JWT token that is just inserted into the header if HTTP/2 protocol is used. Again, as far as I understood certificates should be manually renewed every year (which seems error-prone to me) while JWTs have all the parts to be regenerated automatically over indefinitely long periods (or not?). If that's the case, I'd definitely want to try using JWT.
Now, having zero experience with iOS development, no registration in iOS dev program and even no iOS devices, I have a hard time understanding how exactly to concoct the correct JWT. Namely, I don't get what are
"A 10-character key identifier (kid) key, obtained from your developer account"
"The issuer (iss) registered claim key, whose value is your 10-character Team ID, obtained from your developer account"
"After you create the token, you must sign it with a private key."
In the last sentence I don't understand what this private key is.
iOS developers I'm working with are not very enthusiastic about researching this topic, having given me the p12 certificate the way they always had done in the past. So, if I could point them to the right place (preferably pictures or working "paths") saying "send me this and this", my problem will hopefully be solved. If any of these are not readily available in any developer's account and should be arrived at by some process, I'm afraid I'll need these instructions as well (a working reference to docs or your own description would be perfect).
I would be very grateful if you could confirm my assumptions about JWT in general and clarify the missing details to me.
The Key ID and Key is obtained from the Apple Developer account portal. The process is described in the Xcode help and can be found by searching the help for “Configure push notifications.”.
You create a new Push Notification Authentication key in the Developer portal:
Go to Certificates, Identifiers & Profiles, and under Certificates, select All or APNs Auth Key.
Click the Add button (+) in the upper-right corner.
Under Production, select the “Apple Push Notification Authentication Key (Sandbox & Production)” checkbox, and click Continue.
Once you click Continue, you will see the following screen:
The Key ID is the KID referred to in the documentation and when you click Download you will get the private key that is associated with this key ID.
You can use this to generate the token, which is a JSON document with the following format:
{
"alg": "ES256",
"kid": "ABC123DEFG"
}
{
"iss": "DEF123GHIJ",
"iat": 1437179036
}
where kid is the Key ID and iss the team identifier, also from the Developer portal. iat is the issued at time for this token, which is the number of seconds since Epoch, in UTC
After you create the token, you must sign it with the private key that was downloaded from the portal when the kid was generated. You must then encrypt the token using the Elliptic Curve Digital Signature Algorithm (ECDSA) with the P-256 curve and the SHA-256 hash algorithm.
To ensure security, APNs requires new tokens to be generated periodically. A new token has an updated issued at claim key, whose value indicates the time the token was generated. If the timestamp for token issue is not within the last hour, APNs rejects subsequent push messages, returning an ExpiredProviderToken (403) error.
For iOS applications that require push notifications, it must first request the user for permission to do so. After that, a device token is generated and with this, the remote server may communicate to the user through this token.
I have read a similar question here and I do not feel it is enough. The picture below is a trusted certificate, it allows me to view all traffic that happens on this device.
With Fiddler2 as well as CertMaker, I can sniff HTTPS traffic, which means the client can probably know what data they are sending, and to where.
My question is, knowing that SSL is not secure from protecting my clients from seeing what I send to the remote server, should I simply encypt with a secret key found within my application?
Such as encrypt("device_token","secretkey_a0a0a0a") (pretend this is Objective-C)?
Couldn't someone just find that key within my application? I also read this question, and it seems that it would be possible to get back the secret key.
My plan for this goes like this:
Within the iOS application, Generate a random string named activate.
Encrypt (not hash), the token by the random string and a secret key that I only know. (secretkey_a0a0a0)
Send the encrypted string along with the generated randomly generated string (active).
Within serverside, I check if I can decrypt a valid token from using the active and my secret key.
I save the token in my database if it is valid.
This prevents people from random entering tokens yes, however, secretkey_a0a0a0 is a string literal. It's very possible to get this within the application binary itself.
My question is, how do I protect this secret key? The answer can also be, how can I prevent people from sending invalid tokens to my server as well.
I have heard of encryption, but doesn't that only apply to resource files?
How should I approach this?
If you do SSL-Pinning ( AFNetworking has this implemented ) you won't be able to (in a reasonable timeframe) sniff the https traffic between the client and server if you don't have the servers private key.
If your fear is that man in the middle can steal your token and send fake push notifications to users of your application, be sure that this cant happend. Since requests to apple apn servers must be signed with pem file, the main concern should be how to keep certificate file secured, and not apn token. If you want to prevent writing invalid tokens in your database then you should implement some CRC or odd/even bit mechanism.
You might want to check the security section in the Push Notifications Guide, in particular the section titled "Token Generation and Dispersal".
The device token is generated by the device connecting through the Apple's APNS. My guess (they don't say in the docs) is that it's unique for a given app identifier.
The APNS then will probably match those identifiers with the pem certificate you use to communicate with it thus validating that the push notifications are actually originating from your app.
Encrypting the device token seems overkill in this scenario.
To prevent someone maliciously spamming your server with tokens, I would hash the token when a secret key and send both the token and the hash to the server. You can then hash the token again on the server, with your secret key, and check that the request is valid.