字节跳动技术训练营-安全与风控专场-笔试题解
字节跳动技术训练营-安全与风控专场-笔试题解
最近寒假没事干,水一波字节的这个训练营。假期学习一波。
主要分为三部分,单选,多选,代码题目。
单选以及多选这里没太过注意,就记了几道感觉有歧义的题目。给大家分享一下我的思路(没答案,不知道对错,欢迎大佬指正。
欢迎各位大佬交流答疑。
单选
题目一、判断Origin
这道题考察了在进行过滤时会产生的一些问题。我简单来说一下。
疑问点:题目中告诉了,以下都是判断Origin的表达式,所以题目中出现request_origin和domain其实都是一个东西?
A选项: 可以通过 www.tiktok.fake.com来进行绕过。
B选项: 这个是A选项的一个进阶版本,但也还可以通过 www.faketiktok.com来进行绕过。
C选项:我感觉是对的
D选项:在这里需要提以下origin和referer的区别了,referer里面会有url,但origin中却是host,也就是域名。所以该正则无法正常匹配。
题目二、命令注入
在这题里面,我选择的是C。
疑问点:C明明是nodejs,但注释却写是php。
A选项:Java在使用Runtime.getRuntime().exec()时,如果参数为字符串,那只能执行一个命令。其他逃逸符号,如&&,||,;等符号,均无效。在这里其使用的是ls,我们只能从其参数来做手脚。所以错误。
B选项:这个在我这边算是一个迷惑项,因为对Go了解比较少吧。但猜测跟D选项差不多。
C选项:在nodejs中,exec就是比较正常的执行命令。没记错的话,他应该是直接调用的/bin/sh -c来执行的命令。所以我们可以通过&&,||等符号来继续连接,进而执行命令。
D选项:当在Python中对Popen进行传参时,默认第一个是命令,后面的都是参数。所以和A差不多。
题目三、CSRF相关问题
在这题里面,我选择的是D。
ABC就不多说了,常规修复方法。在这里,主要是D我这边有所疑问。
题中没有说此处Content-type是Request的还是Response的。如果是Request的,其实其对于CSRF防御还是有一定的效果。因为目前CSRF构造json请求还算是比较大的一个难题吧。
在这里提一下跨域吧,CSRF利用的其实就是跨域的一个问题,A网站自动通过用户浏览器向B网站发送构造的数据包。当为简单请求时,请求会直接发送到服务器。但响应包会被浏览器拦截,因为其触发了跨域。所以我们CSRF通常是用来去进行一些敏感操作,如改密码,添加管理员等。
但在这里,因为json请求属于复杂请求,其会预先发送OPTIONS请求预检。在预检测时,请求即被浏览器所拦截。所以真正的攻击请求不会被发送。
目前我所知道的方法,只有通过flash来发起,但2021年后,flash全面暂停。所以意味着该攻击方法其实在一定程度上,算是无法复现的。(不知道大佬们还有没有什么其他方法推荐
多选
题目一、文件上传
这题我是全选了,BCD其实比较好理解,主要是A选项。当文件上传上传HTML时,其实可以视为是一个存储型xss了。因为我们可以获得到,用户访问当前域的一些资料。满足跨站脚本这个概念了。(之前含泪把文件上传交过存储型XSS
编程题
第一题、
题目忘记了,如果有大佬记住,麻烦评论区帮忙补一下。
这题比较简单,我是直接取出?处的位置坐标,然后判断检查串当前位置值是否在seed中。
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param seed string字符串 种子串
# @param token string字符串 token串
# @param req string字符串 输出检查串
# @return bool布尔型
#
class Solution:
def checkToken(self , seed , token , req ):
indexList = []
for i in range(len(token)):
if(token[i]=="?"):
indexList.append(i)
for index in indexList:
flag = 0
for j in seed:
if(req[index] == j):
flag = 1
if(flag == 0 ):
print("false")
return False
print("true")
return True
# write code here
# 测试用例:
# "abc","a??bbcabc","aacbbcabc"
# true
第二题、
这题在做的时候看了半天没看懂,另外一开始给的测试用例也是有问题的。(不知道大家发现右下角有个考试问题咨询的按钮了么、和客服又要了份测试用例。
# 输入 5,3,[1,3,4] # 输出 [1,2,4]
然而看了半天,还是没懂,赛后问另一个朋友,才勉强理解了。在这里也补一下吧。
其实这个题是给新员工腾位置的题目,每次轮询,就是来了一个新人的意思。题目要求,新人必须都坐到最右面。然后这道题就有解了。
我们来看一下测试用例,理解一下。
首先一开始是5个人、然后需要进行三次位置变更。
座位号:1 2 3 4 5 6 7 8 9
第零次:1 0 2 0 3 0 4 0 5 (题中说了,最后一个是n所以右边不可能有座位
第一次:1 0 2 0 3 0 4 5 0 5号最右面,到8,问1号位做的是谁:可知1号
第二次:1 0 2 0 3 5 4 0 0 5号最右面,到6,问3号位做的是谁:可知2号
第二次:1 0 2 4 3 5 0 0 0 4号最右面,到4,问4号位做的是谁:可知4号
理解了之后,编码还是比较简单的。
# coding:utf-8
# 输入 5,3,[1,3,4]
# 输出 [1,2,4]
def main(n,q,req):
people = []
returnList = []
# 初始化集合
for i in range(1,n):
people.append(i)
people.append(0)
people.append(n)
# 开始排序
for i in range(q):
for j in range(len(people))[::-1]:
if(people[j] == 0):
continue
else:
for n in range(j)[::-1]:
if(people[n]==0):
people[n] = people[j]
break
people[j] = 0
break
returnList.append(people[req[i]-1])
print(returnList)
return returnList
main(5,3,[1,3,4])
第三题、
这道题我是直接按照掩码的概念,将ip转化为2进制,然后按照掩码位数取出前缀。
比如:10.10.10.10/24
其中10.10.10.10转化为2进制为00001010 00001010 00001010 00001010
然后取前24位入库,如deny_list,00001010 00001010 00001010。
然后将输入ip与其进行比较,如:10.10.10.132和10.20.10.11,这两个。
我们继续将ip转为2进制:10.10.10.132 -> 00001010 00001010 00001010 1000010010.20.10.10 -> 00001010 00010100 00001010 10000100
之后将其与库中的所有内容相比,判断库中内容是否是其开头部分,即可确定是否在其范围内
详细代码如下:
# coding:utf-8
class Solution:
def __init__(self):
self.deny_list = []
self.allow_list = []
def resolveMask(self,ip,mask):
# 解析掩码
parse_ip = ""
tmp_ip_list = ip.split(".")
for i in tmp_ip_list:
parse_ip += bin(int(i))[2:].zfill(8)
if(mask):
return parse_ip[:int(mask)]
return parse_ip
def getRules(self,rules):
for rule in rules:
r,i = rule.split(" ") # 分割指令与值
# 解析规则
if(len(i.split("/")) > 1):
ip,mask = i.split("/")
else:
ip = i
mask = ""
ip_list = self.resolveMask(ip,mask)
print(ip_list)
# 规则入库分类
if(r == "deny"):
self.deny_list.append(ip_list)
elif(r == "allow"):
self.allow_list.append(ip_list)
def checkIPs(self, rules , ips ):
self.getRules(rules)
print(self.deny_list)
return_list = []
for i in ips:
# 格式化输入ip
check = ""
tmp_ip_list = i.split(".")
for kk in tmp_ip_list:
check += bin(int(kk))[2:].zfill(8)
flag = 1
# 取出deny并进行对比
for j in self.deny_list:
print("d-",j)
print("d+",check[:len(j)])
print("")
if(j == check[:len(j)]):
flag = 0
# 取出allow并进行对比
for j in self.allow_list:
print("a-",j)
print("a+",check[:len(j)])
print("")
if(j == check[:len(j)]):
flag = 1
if(flag == 0):
return_list.append("deny")
else:
return_list.append("allow")
# break
print(return_list)
return return_list
s = Solution()
s.checkIPs(["allow 1.2.3.4/30","deny 1.1.1.1","allow 127.0.0.1","allow 123.234.12.23/3","deny 0.0.0.0/0"],["1.2.3.4","1.2.3.5","1.1.1.1"]) #笔试题目##字节跳动#
查看3道真题和解析
