fix: authentication bypass and denial of service (DoS) vulnerabilities in Apple Game Center auth adapter (GHSA-qf8x-vqjv-92gr) (#7962)
This commit is contained in:
@@ -1665,11 +1665,7 @@ describe('Apple Game Center Auth adapter', () => {
|
|||||||
bundleId: 'cloud.xtralife.gamecenterauth',
|
bundleId: 'cloud.xtralife.gamecenterauth',
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
await gcenter.validateAuthData(authData);
|
||||||
await gcenter.validateAuthData(authData);
|
|
||||||
} catch (e) {
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('validateAuthData invalid signature id', async () => {
|
it('validateAuthData invalid signature id', async () => {
|
||||||
@@ -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 () => {
|
it('validateAuthData invalid public key http url', async () => {
|
||||||
const authData = {
|
const publicKeyUrls = [
|
||||||
id: 'G:1965586982',
|
'example.com',
|
||||||
publicKeyUrl: 'http://static.gc.apple.com/public-key/gc-prod-4.cer',
|
'http://static.gc.apple.com/public-key/gc-prod-4.cer',
|
||||||
timestamp: 1565257031287,
|
'https://developer.apple.com/assets/elements/badges/download-on-the-app-store.svg',
|
||||||
signature: '1234',
|
'https://example.com/ \\.apple.com/public_key.cer',
|
||||||
salt: 'DzqqrQ==',
|
'https://example.com/ &.apple.com/public_key.cer',
|
||||||
bundleId: 'cloud.xtralife.gamecenterauth',
|
];
|
||||||
};
|
await Promise.all(
|
||||||
|
publicKeyUrls.map(publicKeyUrl =>
|
||||||
try {
|
expectAsync(
|
||||||
await gcenter.validateAuthData(authData);
|
gcenter.validateAuthData({
|
||||||
fail();
|
id: 'G:1965586982',
|
||||||
} catch (e) {
|
timestamp: 1565257031287,
|
||||||
expect(e.message).toBe(
|
publicKeyUrl,
|
||||||
'Apple Game Center - invalid publicKeyUrl: http://static.gc.apple.com/public-key/gc-prod-4.cer'
|
signature: '1234',
|
||||||
);
|
salt: 'DzqqrQ==',
|
||||||
}
|
bundleId: 'com.example.com',
|
||||||
|
})
|
||||||
|
).toBeRejectedWith(
|
||||||
|
new Parse.Error(
|
||||||
|
Parse.Error.SCRIPT_FAILED,
|
||||||
|
`Apple Game Center - invalid publicKeyUrl: ${publicKeyUrl}`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -19,15 +19,8 @@ const cache = {}; // (publicKey -> cert) cache
|
|||||||
|
|
||||||
function verifyPublicKeyUrl(publicKeyUrl) {
|
function verifyPublicKeyUrl(publicKeyUrl) {
|
||||||
try {
|
try {
|
||||||
const parsedUrl = new URL(publicKeyUrl);
|
const regex = /^https:\/\/(?:[-_A-Za-z0-9]+\.){0,}apple\.com\/.*\.cer$/;
|
||||||
if (parsedUrl.protocol !== 'https:') {
|
return regex.test(publicKeyUrl);
|
||||||
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';
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -43,7 +36,7 @@ function convertX509CertToPEM(X509Cert) {
|
|||||||
return pemPreFix + certBody + pemPostFix;
|
return pemPreFix + certBody + pemPostFix;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAppleCertificate(publicKeyUrl) {
|
async function getAppleCertificate(publicKeyUrl) {
|
||||||
if (!verifyPublicKeyUrl(publicKeyUrl)) {
|
if (!verifyPublicKeyUrl(publicKeyUrl)) {
|
||||||
throw new Parse.Error(
|
throw new Parse.Error(
|
||||||
Parse.Error.OBJECT_NOT_FOUND,
|
Parse.Error.OBJECT_NOT_FOUND,
|
||||||
@@ -53,6 +46,25 @@ function getAppleCertificate(publicKeyUrl) {
|
|||||||
if (cache[publicKeyUrl]) {
|
if (cache[publicKeyUrl]) {
|
||||||
return 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) => {
|
return new Promise((resolve, reject) => {
|
||||||
https
|
https
|
||||||
.get(publicKeyUrl, res => {
|
.get(publicKeyUrl, res => {
|
||||||
|
|||||||
Reference in New Issue
Block a user