字节跳动技术训练营-安全与风控专场-笔试题解
最近寒假没事干,水一波字节的这个训练营。假期学习一波。
主要分为三部分,单选,多选,代码题目。
单选以及多选这里没太过注意,就记了几道感觉有歧义的题目。给大家分享一下我的思路(没答案,不知道对错,欢迎大佬指正。
欢迎各位大佬交流答疑。
单选
题目一、判断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 10000100
10.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"])
全部评论
(0) 回帖