Skip to content

Commit 1930a64

Browse files
authored
fix: authentication bypass and denial of service (DoS) vulnerabilities in Apple Game Center auth adapter (GHSA-qf8x-vqjv-92gr) (#7963)
1 parent cd354b7 commit 1930a64

File tree

2 files changed

+52
-30
lines changed

2 files changed

+52
-30
lines changed

spec/AuthenticationAdapters.spec.js

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,11 +1657,7 @@ describe('Apple Game Center Auth adapter', () => {
16571657
bundleId: 'cloud.xtralife.gamecenterauth',
16581658
};
16591659

1660-
try {
1661-
await gcenter.validateAuthData(authData);
1662-
} catch (e) {
1663-
fail();
1664-
}
1660+
await gcenter.validateAuthData(authData);
16651661
});
16661662

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

1685-
it('validateAuthData invalid public key url', async () => {
1686-
const authData = {
1687-
id: 'G:1965586982',
1688-
publicKeyUrl: 'invalid.com',
1689-
timestamp: 1565257031287,
1690-
signature: '1234',
1691-
salt: 'DzqqrQ==',
1692-
bundleId: 'cloud.xtralife.gamecenterauth',
1693-
};
1694-
1695-
try {
1696-
await gcenter.validateAuthData(authData);
1697-
fail();
1698-
} catch (e) {
1699-
expect(e.message).toBe('Apple Game Center - invalid publicKeyUrl: invalid.com');
1700-
}
1681+
it('validateAuthData invalid public key http url', async () => {
1682+
const publicKeyUrls = [
1683+
'example.com',
1684+
'http://static.gc.apple.com/public-key/gc-prod-4.cer',
1685+
'https://developer.apple.com/assets/elements/badges/download-on-the-app-store.svg',
1686+
'https://example.com/ \\.apple.com/public_key.cer',
1687+
'https://example.com/ &.apple.com/public_key.cer',
1688+
];
1689+
await Promise.all(
1690+
publicKeyUrls.map(publicKeyUrl =>
1691+
expectAsync(
1692+
gcenter.validateAuthData({
1693+
id: 'G:1965586982',
1694+
timestamp: 1565257031287,
1695+
publicKeyUrl,
1696+
signature: '1234',
1697+
salt: 'DzqqrQ==',
1698+
bundleId: 'com.example.com',
1699+
})
1700+
).toBeRejectedWith(
1701+
new Parse.Error(
1702+
Parse.Error.SCRIPT_FAILED,
1703+
`Apple Game Center - invalid publicKeyUrl: ${publicKeyUrl}`
1704+
)
1705+
)
1706+
)
1707+
);
17011708
});
17021709
});
17031710

src/Adapters/Auth/gcenter.js

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,16 @@ const authData = {
1414
const { Parse } = require('parse/node');
1515
const crypto = require('crypto');
1616
const https = require('https');
17-
const url = require('url');
1817

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

2120
function verifyPublicKeyUrl(publicKeyUrl) {
22-
const parsedUrl = url.parse(publicKeyUrl);
23-
if (parsedUrl.protocol !== 'https:') {
21+
try {
22+
const regex = /^https:\/\/(?:[-_A-Za-z0-9]+\.){0,}apple\.com\/.*\.cer$/;
23+
return regex.test(publicKeyUrl);
24+
} catch (error) {
2425
return false;
2526
}
26-
const hostnameParts = parsedUrl.hostname.split('.');
27-
const length = hostnameParts.length;
28-
const domainParts = hostnameParts.slice(length - 2, length);
29-
const domain = domainParts.join('.');
30-
return domain === 'apple.com';
3127
}
3228

3329
function convertX509CertToPEM(X509Cert) {
@@ -40,7 +36,7 @@ function convertX509CertToPEM(X509Cert) {
4036
return pemPreFix + certBody + pemPostFix;
4137
}
4238

43-
function getAppleCertificate(publicKeyUrl) {
39+
async function getAppleCertificate(publicKeyUrl) {
4440
if (!verifyPublicKeyUrl(publicKeyUrl)) {
4541
throw new Parse.Error(
4642
Parse.Error.OBJECT_NOT_FOUND,
@@ -50,6 +46,25 @@ function getAppleCertificate(publicKeyUrl) {
5046
if (cache[publicKeyUrl]) {
5147
return cache[publicKeyUrl];
5248
}
49+
const url = new URL(publicKeyUrl);
50+
const headOptions = {
51+
hostname: url.hostname,
52+
path: url.pathname,
53+
method: 'HEAD',
54+
};
55+
const headers = await new Promise((resolve, reject) =>
56+
https.get(headOptions, res => resolve(res.headers)).on('error', reject)
57+
);
58+
if (
59+
headers['content-type'] !== 'application/pkix-cert' ||
60+
headers['content-length'] == null ||
61+
headers['content-length'] > 10000
62+
) {
63+
throw new Parse.Error(
64+
Parse.Error.OBJECT_NOT_FOUND,
65+
`Apple Game Center - invalid publicKeyUrl: ${publicKeyUrl}`
66+
);
67+
}
5368
return new Promise((resolve, reject) => {
5469
https
5570
.get(publicKeyUrl, res => {

0 commit comments

Comments
 (0)