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) (#7962)
  • Loading branch information
mtrezza committed May 1, 2022
1 parent 852bb47 commit af4a041
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 50 deletions.
67 changes: 27 additions & 40 deletions spec/AuthenticationAdapters.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1665,11 +1665,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 @@ -1690,42 +1686,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 authData = {
id: 'G:1965586982',
publicKeyUrl: 'http://static.gc.apple.com/public-key/gc-prod-4.cer',
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: http://static.gc.apple.com/public-key/gc-prod-4.cer'
);
}
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
32 changes: 22 additions & 10 deletions src/Adapters/Auth/gcenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,8 @@ const cache = {}; // (publicKey -> cert) cache

function verifyPublicKeyUrl(publicKeyUrl) {
try {
const parsedUrl = new URL(publicKeyUrl);
if (parsedUrl.protocol !== 'https:') {
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';
const regex = /^https:\/\/(?:[-_A-Za-z0-9]+\.){0,}apple\.com\/.*\.cer$/;
return regex.test(publicKeyUrl);
} catch (error) {
return false;
}
Expand All @@ -43,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 @@ -53,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 af4a041

Please sign in to comment.