首页 > 笔经面经 > 字节跳动技术训练营-安全与风控专场-笔试题解

字节跳动技术训练营-安全与风控专场-笔试题解

头像
丶诺熙
编辑于 2021-01-23 19:52:15 APP内打开
赞 4 | 收藏 8 | 回复0 | 浏览1401

字节跳动技术训练营-安全与风控专场-笔试题解

最近寒假没事干,水一波字节的这个训练营。假期学习一波。

主要分为三部分,单选,多选,代码题目。

单选以及多选这里没太过注意,就记了几道感觉有歧义的题目。给大家分享一下我的思路(没答案,不知道对错,欢迎大佬指正

欢迎各位大佬交流答疑。

单选

题目一、判断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.13210.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条回帖

回帖
加载中...
话题 回帖

相关热帖

笔经面经近期热帖

历年真题 真题热练榜 24小时
技术(软件)/信息技术类
查看全部

近期精华帖

热门推荐