GramJS: Add more security checks (#3419)

This commit is contained in:
Alexander Zinchuk 2023-07-05 13:16:06 +02:00
parent 6d8f415bc1
commit 823fd9add7
5 changed files with 34 additions and 9 deletions

View File

@ -100,7 +100,7 @@ export function getUserStatus(
if (!wasOnline) return lang('LastSeen.Offline');
const serverTimeOffset = getServerTimeOffset();
const now = new Date(new Date().getTime() + serverTimeOffset * 1000);
const now = new Date(Date.now() + serverTimeOffset * 1000);
const wasOnlineDate = new Date(wasOnline * 1000);
if (wasOnlineDate >= now) {

View File

@ -291,7 +291,7 @@ class TelegramClient {
// for Telegram to keep delivering updates, otherwise they will
// just stop even if we're connected. Do so every 30 minutes.
if (new Date().getTime() - this._lastRequest > 30 * 60 * 1000) {
if (Date.now() - this._lastRequest > 30 * 60 * 1000) {
try {
await this.pingCallback();
} catch (e) {
@ -877,7 +877,7 @@ class TelegramClient {
}
const sender = dcId === undefined ? this._sender : await this.getSender(dcId);
this._lastRequest = new Date().getTime();
this._lastRequest = Date.now();
const state = new RequestState(request, abortSignal);

View File

@ -156,11 +156,15 @@ export async function doAuthentication(sender: MTProtoPlainSender, log: any) {
const ige = new IGE(key, iv);
const plainTextAnswer = ige.decryptIge(serverDhParams.encryptedAnswer);
const reader = new BinaryReader(plainTextAnswer);
reader.read(20); // hash sum
const hash = reader.read(20); // hash sum
const serverDhInner = reader.tgReadObject();
if (!(serverDhInner instanceof Api.ServerDHInnerData)) {
throw new Error(`Step 3 answer was ${serverDhInner}`);
}
const sha1Answer = await Helpers.sha1(serverDhInner.getBytes());
if (!(hash.equals(sha1Answer))) {
throw new SecurityError('Step 3 Invalid hash answer');
}
if (serverDhInner.nonce.neq(resPQ.nonce)) {
throw new SecurityError('Step 3 Invalid nonce in encrypted answer');
@ -185,7 +189,7 @@ export async function doAuthentication(sender: MTProtoPlainSender, log: any) {
false,
);
const ga = Helpers.readBigIntFromBuffer(serverDhInner.gA, false, false);
const timeOffset = serverDhInner.serverTime - Math.floor(new Date().getTime() / 1000);
const timeOffset = serverDhInner.serverTime - Math.floor(Date.now() / 1000);
const b = Helpers.readBigIntFromBuffer(
Helpers.generateRandomBytes(256),
false,

View File

@ -284,6 +284,16 @@ class MTProtoState {
// reader isn't used for anything else after this, it's unnecessary.
const obj = reader.tgReadObject();
// We only check for objects that telegram has returned to us (Updates) not ones we send.
if (obj?.constructor.name.startsWith('Update')) {
const now = Math.floor(Date.now() / 1000);
const msgLocalTime = this.getMsgIdTimeLocal(remoteMsgId);
if (msgLocalTime && ((msgLocalTime - now) > 30 || (now - msgLocalTime) > 300)) {
// 30 sec in the future or 300 sec in the past
throw new SecurityError('The message time is incorrect.');
}
}
return new TLMessage(remoteMsgId, remoteSequence, obj);
}
}
@ -294,7 +304,7 @@ class MTProtoState {
* @private
*/
_getNewMsgId() {
const now = new Date().getTime() / 1000 + this.timeOffset;
const now = Date.now() / 1000 + this.timeOffset;
const nanoseconds = Math.floor((now - Math.floor(now)) * 1e9);
let newMsgId = (BigInt(Math.floor(now))
.shiftLeft(BigInt(32))).or(BigInt(nanoseconds)
@ -306,6 +316,17 @@ class MTProtoState {
return newMsgId;
}
/**
* Returns the understood time by the message id (server time + local offset)
*/
getMsgIdTimeLocal(msgId) {
if (this._lastMsgId.eq(0)) {
// this means it's the first message sent/received so don't check yet
return false;
}
return msgId.shiftRight(BigInt(32)).toJSNumber() - this.timeOffset;
}
/**
* Updates the time offset to the correct
* one given a known valid message ID.
@ -314,7 +335,7 @@ class MTProtoState {
updateTimeOffset(correctMsgId) {
const bad = this._getNewMsgId();
const old = this.timeOffset;
const now = Math.floor(new Date().getTime() / 1000);
const now = Math.floor(Date.now() / 1000);
const correct = correctMsgId.shiftRight(BigInt(32));
this.timeOffset = correct - now;

View File

@ -17,7 +17,7 @@ class MTProtoRequest {
// these should not be overrode
onSendSuccess() {
this.sendTime = new Date().getTime();
this.sendTime = Date.now();
this.sent = true;
}
@ -26,7 +26,7 @@ class MTProtoRequest {
}
needResend() {
return this.dirty || (this.confirmed && !this.confirmReceived && new Date().getTime() - this.sendTime > 3000);
return this.dirty || (this.confirmed && !this.confirmReceived && Date.now() - this.sendTime > 3000);
}
// These should be overrode