我只是好奇這件事。 strtol
並不要求你指定要處理的字節數,所以理論上它可能被送入一個包含無盡數字的字符串消耗,導致拒絕服務攻擊。當然,通過意識到長時間精度已經被耗盡(不能超過65個字符的二進制數字),很容易被挫敗,因此沒有任何進一步閱讀的意義。`strtol`的實現是什麼?
但是,strtol
也需要根據需要丟棄儘可能多的空白字符,直到遇到第一個非空白字符。那麼即使閱讀數字很聰明,它是否可以不受無盡空白字符串的攻擊?
我只是好奇這件事。 strtol
並不要求你指定要處理的字節數,所以理論上它可能被送入一個包含無盡數字的字符串消耗,導致拒絕服務攻擊。當然,通過意識到長時間精度已經被耗盡(不能超過65個字符的二進制數字),很容易被挫敗,因此沒有任何進一步閱讀的意義。`strtol`的實現是什麼?
但是,strtol
也需要根據需要丟棄儘可能多的空白字符,直到遇到第一個非空白字符。那麼即使閱讀數字很聰明,它是否可以不受無盡空白字符串的攻擊?
然而這個與strtol,還需要strtol將在必要時,直到第一個非空白字符丟棄儘可能多的空白字符遇到。那麼即使閱讀數字很聰明,它是否可以不受無盡空白字符串的攻擊?
由於strtol
作品上的繩子已經在內存中,你將不得不存儲(從攻擊者讀取)空白的「永無止境」的金額(或忘記NUL,終止您的字符串)之前,甚至將其送入與strtol。
由於實現可以保持計算可以存在於有效字符串中的最大位數,因此您不必繼續前進。
DOS攻擊可能會出現錯誤的實現,儘管如此,請查看this相關案例(這是在Java和PHP中讀取雙精度數據時,但在C或C++實現中可能會發生的情況)。
strtol
沒有單一的實現。我懷疑任何實現都不容易受到你描述的那種攻擊的影響;顯而易見的實現只會遍歷數字序列,而不會一次全部存儲它們。 (請注意,由於領先的0
s,數字序列可以任意長。)
如果您想查看實現的代碼,可以下載glibc版本here; strtol()
在stdlib/strtol.c
。
那麼,如果你想看看你可以通過大學看到加州
/*
* strtol.c --
*
* Source code for the "strtol" library procedure.
*
* Copyright (c) 1988 The Regents of the University of California.
* All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
* CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
static const char rcsid[] = "$Header$ SPRITE (Berkeley)";
#include <ctype.h>
extern unsigned long int strtoul(char *string, char **endPtr, int base);
/*
*----------------------------------------------------------------------
*
* strtol --
*
* Convert an ASCII string into an integer.
*
* Results:
* The return value is the integer equivalent of string. If endPtr
* is non-NULL, then *endPtr is filled in with the character
* after the last one that was part of the integer. If string
* doesn't contain a valid integer value, then zero is returned
* and *endPtr is set to string.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
long int
strtol(
char *string, /* String of ASCII digits, possibly
* preceded by white space. For bases
* greater than 10, either lower- or
* upper-case digits may be used.
*/
char **endPtr, /* Where to store address of terminating
* character, or NULL. */
int base /* Base for conversion. Must be less
* than 37. If 0, then the base is chosen
* from the leading characters of string:
* "0x" means hex, "0" means octal, anything
* else means decimal.
*/
)
{
register char *p;
int result;
/*
* Skip any leading blanks.
*/
p = string;
while (isspace(*p)) {
p += 1;
}
/*
* Check for a sign.
*/
if (*p == '-') {
p += 1;
result = -1*(strtoul(p, endPtr, base));
} else {
if (*p == '+') {
p += 1;
}
result = strtoul(p, endPtr, base);
}
if ((result == 0) && (endPtr != 0) && (*endPtr == p)) {
*endPtr = string;
}
return result;
}
我的個人實施。我沒有使用任何lookahead(訪問p[1]
或類似的東西),因此理論上你可以將它轉換爲從流中讀取的內容(例如,get_long()
,它爲字符調用getc()
)。
#include <errno.h>
#define LONG_MAX ((long)(~0UL>>1))
#define LONG_MIN (~LONG_MAX)
int isspace(int c); /* <-- Forward declare from <ctype.h> */
long strtol(const char *restrict nptr, char **restrict endptr, int base) {
const char *p = nptr, *endp;
_Bool is_neg = 0, overflow = 0;
/* Need unsigned so (-LONG_MIN) can fit in these: */
unsigned long n = 0UL, cutoff;
int cutlim;
if (base < 0 || base == 1 || base > 36) {
#ifdef EINVAL /* errno value defined by POSIX */
errno = EINVAL;
#endif
return 0L;
}
endp = nptr;
while (isspace(*p))
p++;
if (*p == '+') {
p++;
} else if (*p == '-') {
is_neg = 1, p++;
}
if (*p == '0') {
p++;
/* For strtol(" 0xZ", &endptr, 16), endptr should point to 'x';
* pointing to ' ' or '0' is non-compliant.
* (Many implementations do this wrong.) */
endp = p;
if (base == 16 && (*p == 'X' || *p == 'x')) {
p++;
} else if (base == 0) {
if (*p == 'X' || *p == 'x') {
base = 16, p++;
} else {
base = 8;
}
}
} else if (base == 0) {
base = 10;
}
cutoff = (is_neg) ? -(LONG_MIN/base) : LONG_MAX/base;
cutlim = (is_neg) ? -(LONG_MIN % base) : LONG_MAX % base;
while (1) {
int c;
if (*p >= 'A')
digit = ((*p - 'A') & (~('a'^'A'))) + 10;
else if (*p <= '9')
digit = *p - '0';
else
break;
if (c < 0 || c >= base) break;
endp = ++p;
if (overflow) {
/* endptr should go forward and point to the non-digit character
* (of the given base); required by ANSI standard. */
if (endptr) continue;
break;
}
if (n > cutoff || (n == cutoff && c > cutlim)) {
overflow = 1; continue;
}
n = n * base + c;
}
if (endptr) *endptr = (char *)endp;
if (overflow) {
errno = ERANGE; return ((is_neg) ? LONG_MIN : LONG_MAX);
}
return (long)((is_neg) ? -n : n);
}
你的「無盡的」空白字符串需要無盡的記憶。 [Here](ftp://ftp.irisa.fr/pub/OpenBSD/src/sys/lib/libsa/strtol.c)是一個實現的例子。不讀太多數字確實很聰明。 – user786653
你應該驗證你給strtol的參數 - 就像你應該使用大多數庫函數一樣。例如1.參數必須是一個字符串(即它必須以nul結尾)。如果它涉及到你,請確認你沒有給它一個無限長的字符串。 – nos
使用'fgets()'(和'sscanf()')來讀取用戶輸入! – pmg