我正在编写一个拒绝访问未授权用户的安全系统。
import sys
print("Hello. Please enter your name:")
name = sys.stdin.readline().strip()
if name == "Kevin" or "Jon" or "Inbar":
print("Access granted.")
else:
print("Access denied.")
它按预期授予对授权用户的访问权限,但也允许未经授权的用户访问!
Hello. Please enter your name:
Bob
Access granted.
为什么会这样?我明确表示只在name
等于Kevin,Jon或Inbar时授予访问权限。我也尝试过相反的逻辑if "Kevin" or "Jon" or "Inbar" == name
,但结果是一样的。
答案 0 :(得分:128)
在许多情况下,Python看起来和行为都像自然英语,但这是抽象失败的一种情况。人们可以使用上下文线索来确定“Jon”和“Inbar”是加入动词“equals”的对象,但Python解释器更具有文字意识。
if name == "Kevin" or "Jon" or "Inbar":
在逻辑上等同于:
if (name == "Kevin") or ("Jon") or ("Inbar"):
对于用户Bob来说,相当于:
if (False) or ("Jon") or ("Inbar"):
or
运算符选择带有正truth value的第一个参数:
if ("Jon"):
由于“Jon”具有正的真值,因此执行if
块。这就是导致“授予访问权限”被打印的原因,无论给出的名称如何。
所有这些推理也适用于表达式if "Kevin" or "Jon" or "Inbar" == name
。第一个值"Kevin"
为true,因此if
块执行。
正确构建此条件有两种常用方法。
使用多个==
运算符明确检查每个值:
if name == "Kevin" or name == "Jon" or name == "Inbar":
撰写一系列有效值,并使用in
运算符测试成员资格:
if name in ("Kevin", "Jon", "Inbar"):
一般来说,第二个应该是首选,因为它更容易阅读,也更快:
In [1]: name = "Inbar"
In [2]: %timeit name == "Kevin" or name == "Jon" or name == "Inbar"
10000000 loops, best of 3: 116 ns per loop
In [3]: %timeit name in ("Kevin", "Jon", "Inbar")
10000000 loops, best of 3: 65.2 ns per loop
答案 1 :(得分:2)
if name == "Kevin" or "Jon" or "Inbar":
中有3个条件检查
此if语句等效于
if name == "Kevin":
print("Access granted.")
elif "Jon":
print("Access granted.")
elif "Inbar":
print("Access granted.")
else:
print("Access denied.")
由于elif "Jon"
始终为true,因此可以授予对任何用户的访问权限
您可以使用以下任意一种方法
快速
if name in ["Kevin", "Jon", "Inbar"]:
print("Access granted.")
else:
print("Access denied.")
慢
if name == "Kevin" or name == "Jon" or name == "Inbar":
print("Access granted.")
else:
print("Access denied.")
慢速+不必要的代码
if name == "Kevin":
print("Access granted.")
elif name == "Jon":
print("Access granted.")
elif name == "Inbar":
print("Access granted.")
else:
print("Access denied.")
答案 2 :(得分:1)
因此,当您说:
library(tidyverse)
cleaned_moneygram <- moneygram_prices %>%
as_tibble() %>%
rename(transfer_fee = 9) %>%
rename(destination_country = 2) %>%
separate(time, into = c("year","time"),sep = " ") %>%
mutate(year = substr(year,1,4)) %>%
mutate(year = as.numeric(year)) %>%
mutate(firm = "MoneyGram") %>%
select(c("send_country","destination_country","payment_method","year","exchange_rate","transfer_fee","firm")) %>%
separate(transfer_fee, into = c("value","currency"),sep = " ") %>%
mutate(tfer_fee_usd = case_when(
currency == "USD" ~ value * 1.0,
currency == "EUR" ~ value * 1.2,
currency == "NOK" ~ value * 1170.5,
currency == "UOF" ~ value * 123.2
))
#> Error in as_tibble(.): object 'moneygram_prices' not found
您实际上是在说:
a = "Raul"
if a == "Kevin" or "John" or "Inbar":
pass
由于“ John”和“ Inbar”中的至少一个不是空字符串,因此整个表达式始终返回True!
if "Raul" == "Kevin" or "John" != "" or "Inbar" != "":
pass
或:
a = "Raul"
if a == "Kevin" or a == "John" or a == "Inbar":
pass
答案 3 :(得分:0)
简单的工程问题,让我们再简单一点。
In [1]: a,b,c,d=1,2,3,4
In [2]: a==b
Out[2]: False
但是,Python从C语言继承而来,将非零整数的逻辑值评估为True。
In [11]: if 3:
...: print ("yey")
...:
yey
现在,Python建立在该逻辑的基础上,让您使用诸如或基于整数的逻辑文字
In [9]: False or 3
Out[9]: 3
最后
In [4]: a==b or c or d
Out[4]: 3
正确的编写方式是:
In [13]: if a in (b,c,d):
...: print('Access granted')
为了安全起见,我还建议您不要对密码进行硬编码。
答案 4 :(得分:0)
最简单的方法是消除对比较运算符的需求,并使用列表。在安全系统上,这看起来令人印象深刻,因为您学会了访问ORM。
user = input("Enter name: ")
if user in {"Bob", "Kevin", "Joe"}:
print("Access granted, " + str(user) + ".")
else:
print("Access denied.")
或者,您可以类似于上面的 exact 相同代码,只需将注册用户列表放在自己的列表中即可:
user = input("Enter name: ")
users = {"Bob", "Kevin", "Joe", "a million more users if you like"}
if user in users:
print("Access granted, " + str(user) + ".")
else:
print("Access denied.")
如果您想安全地完成此协议而没有遭受攻击的风险,请设置双重参数。这将检查您的mini-ORM中的first
和last
名称字段,以及一个password
或secret question
键。如果您想有效地延迟加载用户凭据而不进行散列,则可以按以下方式对对象进行排序:
def lazy(i):
j = 0 # For example
while j < i:
yield j
j += 1
循环将仅消耗 产生的值,以节省系统时间和精力:
然后,您可以对迭代列表进行操作:
for j in lazy_range(10):
do_something_here(j)
可以从任何角度解决此问题:内存管理,安全性,或者仅通过有机列表或打包的ORM来解决。
希望这会有所帮助。