Skip to content

Commit

Permalink
fix: authentication bypass and denial of service (DoS) vulnerabilitie…
Browse files Browse the repository at this point in the history
…s in Apple Game Center auth adapter (GHSA-qf8x-vqjv-92gr) (#7963)
  • Loading branch information
mtrezza committed May 1, 2022
1 parent cd354b7 commit 1930a64
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 30 deletions.
49 changes: 28 additions & 21 deletions spec/AuthenticationAdapters.spec.js
Expand Up @@ -1657,11 +1657,7 @@ describe('Apple Game Center Auth adapter', () => {
bundleId: 'cloud.xtralife.gamecenterauth',
};

try {
await gcenter.validateAuthData(authData);
} catch (e) {
fail();
}
await gcenter.validateAuthData(authData);
});

it('validateAuthData invalid signature id', async () => {
Expand All @@ -1682,22 +1678,33 @@ describe('Apple Game Center Auth adapter', () => {
}
});

it('validateAuthData invalid public key url', async () => {
const authData = {
id: 'G:1965586982',
publicKeyUrl: 'invalid.com',
timestamp: 1565257031287,
signature: '1234',
salt: 'DzqqrQ==',
bundleId: 'cloud.xtralife.gamecenterauth',
};

try {
await gcenter.validateAuthData(authData);
fail();
} catch (e) {
expect(e.message).toBe('Apple Game Center - invalid publicKeyUrl: invalid.com');
}
it('validateAuthData invalid public key http url', async () => {
const publicKeyUrls = [
'example.com',
'http://static.gc.apple.com/public-key/gc-prod-4.cer',
'https://developer.apple.com/assets/elements/badges/download-on-the-app-store.svg',
'https://example.com/ \\.apple.com/public_key.cer',
'https://example.com/ &.apple.com/public_key.cer',
];
await Promise.all(
publicKeyUrls.map(publicKeyUrl =>
expectAsync(
gcenter.validateAuthData({
id: 'G:1965586982',
timestamp: 1565257031287,
publicKeyUrl,
signature: '1234',
salt: 'DzqqrQ==',
bundleId: 'com.example.com',
})
).toBeRejectedWith(
new Parse.Error(
Parse.Error.SCRIPT_FAILED,
`Apple Game Center - invalid publicKeyUrl: ${publicKeyUrl}`
)
)
)
);
});
});

Expand Down
33 changes: 24 additions & 9 deletions src/Adapters/Auth/gcenter.js
Expand Up @@ -14,20 +14,16 @@ const authData = {
const { Parse } = require('parse/node');
const crypto = require('crypto');
const https = require('https');
const url = require('url');

const cache = {}; // (publicKey -> cert) cache

function verifyPublicKeyUrl(publicKeyUrl) {
const parsedUrl = url.parse(publicKeyUrl);
if (parsedUrl.protocol !== 'https:') {
try {
const regex = /^https:\/\/(?:[-_A-Za-z0-9]+\.){0,}apple\.com\/.*\.cer$/;
return regex.test(publicKeyUrl);
} catch (error) {
return false;
}
const hostnameParts = parsedUrl.hostname.split('.');
const length = hostnameParts.length;
const domainParts = hostnameParts.slice(length - 2, length);
const domain = domainParts.join('.');
return domain === 'apple.com';
}

function convertX509CertToPEM(X509Cert) {
Expand All @@ -40,7 +36,7 @@ function convertX509CertToPEM(X509Cert) {
return pemPreFix + certBody + pemPostFix;
}

function getAppleCertificate(publicKeyUrl) {
async function getAppleCertificate(publicKeyUrl) {
if (!verifyPublicKeyUrl(publicKeyUrl)) {
throw new Parse.Error(
Parse.Error.OBJECT_NOT_FOUND,
Expand All @@ -50,6 +46,25 @@ function getAppleCertificate(publicKeyUrl) {
if (cache[publicKeyUrl]) {
return cache[publicKeyUrl];
}
const url = new URL(publicKeyUrl);
const headOptions = {
hostname: url.hostname,
path: url.pathname,
method: 'HEAD',
};
const headers = await new Promise((resolve, reject) =>
https.get(headOptions, res => resolve(res.headers)).on('error', reject)
);
if (
headers['content-type'] !== 'application/pkix-cert' ||
headers['content-length'] == null ||
headers['content-length'] > 10000
) {
throw new Parse.Error(
Parse.Error.OBJECT_NOT_FOUND,
`Apple Game Center - invalid publicKeyUrl: ${publicKeyUrl}`
);
}
return new Promise((resolve, reject) => {
https
.get(publicKeyUrl, res => {
Expand Down

0 comments on commit 1930a64

Please sign in to comment.