基于应用日志的扫描器检测实践

基于应用日志的扫描器检测实践

在网络上搜索web扫描器时,各类扫描器工具、扫描攻略玲琅满目,但对扫描器检测方法的内容却少之又少。因此,本文对各类web扫描特特征进行了梳理和总结,并结合苏宁应用防火墙(SNWAF)日志数据,分别展示了规则模型、统计特征模型和基于文本情感分析的深度学习模型在Web扫描器识别上的实践效果,供大家参考。

1. 扫描器概览

Web扫描器通过构造特殊请求的方式,对Web系统可能存在的安全漏洞进行扫描,是渗透工作的必备工具。相关的网络资源有很多的漏扫工具研发和使用的工作,如Nessus、Nikto、SQLmap等,然而扫描器检测的工作却非常少。这里尝试从扫描器检测方向出发,根据扫描器的功能和所产生的请求内容对其进行分类,并提出一种简单有效的检测思路。

1.1 敏感内容扫描

俗话说知己知彼方能百战不殆,当黑客或渗透测试人员面对一个未知站点时,这个站点对他们来说就是一个黑盒。这时候不妨拿敏感内容扫描器先给它来个一把嗦摸摸底,指不定就能扫到有价值信息,找到撬动安全防护缺口的第一把钥匙。

敏感内容扫描器通常具备一些列敏感路径及敏感文件的字典,扫描器利用这些敏感内容字典对站点进行盲扫来判断是否存在这些敏感内容;进一步地,通过响应数据包对站点目录结构及其他信息进行判断,为下一步针对性单点突破作准备。

这里提到了一个字典的概念,字典这个玩意很重要,可以说字典的质量、广度和深度决定了这个扫描器的上限。相对于IP代理、UA伪造、随机放访问时间间隔这些伪装手段来说,敏感内容是固定的,翻来覆去就这么多东西,同时因为请求资源不存在大多数会返回404状态码(有些会触发WAF拦截策略返回403,还有些因为服务器设置了默认跳转状态码为301或302)。攻方选手通常不会构造毫无意义的字典内容来浪费有限的资源和精力,这些字典通常包含如下内容信息(忽略大小写):

  • 敏感目录信息:如/admin/, /phpadmin/, /mysqladmin/, /usr/local/, /etc/passwd/, ...
  • 敏感配置文件:如.bashrc, .bash_history, conf.icn, config.inc, ...
  • 版本文件信息:如/.git/config, /.svn/entries, /.bzr/xxx, ...
  • 备份文件信息:如htpasswd.bak, index.php.bak, database.wsp, backup.zip, ...
  • 密钥文件信息:如/.ssh/id_rsa, /.ssh/known_hosts, id_rsa.pub, authorized_keys, ...
  • 日志文件信息:如/logs/error.log, /logs/auth.log, /var/log/mysql/mysql.log, ...
  • 其他敏感文件:如config.php, system.inc, mysql.inc, shell.php, ...

1.2 Web漏洞扫描

漏洞扫描器通常会与爬虫相结合。首先利用爬虫获取到页面可能存在注入点的接口,然后针对该接口来一个SQl注入、XSS注入、命令注入一把嗦,对于一些安全防护意识低的站点往往能取到最直接的效果。针对这类扫描请求,WAF都能够做到单点正则过滤,理论上会拦截返回大量403状态码,但是扫描器常针对一些新域名或偏僻的域名进行扫描,这些域名往往没有启用WAF攻击防护,因此实际上是有很多是未被拦截的非403状态码。同上述敏感内容扫描,这类请求往往也具备明显的文本特征,下面分别以sql注入、文件包含和XSS跨站扫描举例。

1.2.1 sql注入漏洞扫描

SQL注入攻击是一种注入攻击,它将SQL命令注入到数据层输入,从而影响执行预定义的SQL命令;通过控制部分SQL语句,攻击者可以查询数据库中任何自己需要的数据,利用数据库的一些特性,可以直接获取数据库服务器的系统权限。

首先,判断接口是否存在注入点,如:

  • 若参数ID为数字,加减运算判断是否存在数字型注入
  • 参数后加单双引号,判断返回结果是否报错
  • 添加注释符判断前后是否有报错:如id=1' --+id=1" --+id=1' #id=1" --+
  • 有些参数可能在括号里面,所以也可以在参数后面加单双引号和括号,如id=1') --+id=1") --+id=1') #id=1") --+
  • 参数后面跟or 或者and,判断返回结果是否有变化,如1' or 'a'='a或者and 'a'='a或者1' or 'a'='b或者1' or '1'='2
  • 也可以考虑时间延迟的方法判断是否存在注入,如 1’ and sleep(5)

然后对存在注入漏洞的点利用联合查询一步步获取信息,如:

  • 查询数据库名:id=0’ union select NULL,database(),NULL --+
  • 爆库名:id=0’ union select null,group_concat(schema_name),null from information_schema.schemata --+
  • 爆表名:id=0’ union select null,group_concat(table_name),null from information_schema.tables where table_schema=‘security’ --+
  • 爆字段名:id=0’ union select null,group_concat(column_name),null from information_schema.columns where table_schema=‘security’ and table_name=‘users’ --+

或者通过报错回显查询结果,如:

  • 回显数据库名:and extractvalue(1,concat(0x7e,(select database())))
  • 回显表名:
    and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=‘security’ )))
  • 回显列名:
    and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=‘security’ and table_name=‘users’)))

1.2.2 文件包含漏洞扫描

服务器通过php的特性(函数)去包含任意文件时,由于要包含的这个文件来源过滤不严,从而可以去包含一个恶意文件,非法用户可以构造这个恶意文件来达到恶意的目的,如读取目标主机上的其他文件,远程文件包含可运行的PHP木马,包含一个创建文件的PHP文件,本地文件包含等。

  • Include:包含并运行指定文件,当包含外部文件发生错误时,系统给出警告,但整个php文件继续执行;
  • Require:跟include唯一不同的是,当产生错误时候,include下面继续运行而require停止运行了;
  • Include_once:这个函数跟include函数作用几乎相同,只是他在导入函数之前先检测下该文件是否被导入,如果已经执行一遍那么就不重复执行了;
  • Require_once:这个函数跟require的区别 跟上面所讲的include和include_once一样。

1.2.3 XSS跨站漏洞

跨站脚本攻击是指恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。与正常请求相比,XSS请求也具备明显的文本特征,如<script>alert(0)</script>,<img src=0 onerror=alert(0)>等。

2. 规则模型

扫描器检测与Web攻击检测不同之处在于,扫描是一种持续的行为,我们通过对扫描器持续一段时间的请求进行聚合分析,而Web攻击检测则是把每条请求作为一次独立的事件来判断是否为Web攻击。扫描器在请求不存在的资源时往往会返回状态码404,但实际生产环境中并非如此。尤其是作为电商企业,希望被正面的搜索引擎抓取,返回404的这种方式会对SEO搜索引擎优化产生不利影响,因此多数域名针对这种请求会做3XX的跳转。总体来说,大量返回404的请求往往都是盲扫请求,但仍有大量盲扫请求返回状态码并非404。这里依赖Web请求日志,在一定时间被仅对请求url文本特征进行分析,来识别扫描器。

2.1 正则提取

敏感内容扫描器往往会请求敏感路径、敏感文件等信息,因此首先收集这些信息,然后用正则匹配去你和这些内容。这里分别按照敏感信息的类型进行分类:

class Sensitive(object):"""docstring for Sensitive"""def __init__(self):super(Sensitive, self).__init__()self.patterns = [# 0. 敏感文件re.compile("(((php)?info|php|[mc]oon|dns|payload|mytag_js|cmd|log|my|shell|data|te?mp|settings|default|root|robots?|htaccess|(my)?sql|data(base)?|db|conf(iguration|ig|igs)?|bac?k(up)?|te?mp|pack(age)?|test|web(site)?|old|site|src|code|suning|result|home|ftp|common|sys(tem)?|(htp)?passwd|shadow|ssh|httpd?)\d{,3}\.(php|zip|rar|tar|gz|tgz|bz2|7z))(\?|&|\s|$|\.)",re.I),# 1. 敏感后缀re.compile("(\.(sql|in(i|c)|conf(ig)?|pub|bac?k(up)?|mdb|swp|ssh|old|tag|git(ignore)?|svn|bzr)(\?|&|\s|$))",re.I),# 3. 敏感日志re.compile("(/logs?/(\w+/){0,}[\w_\.-]+log$)", re.I),# 2. adminre.compile("(/_*(sql|my(sql)?|php|db|sha)[+-._\d]*(my)?admins?[+-._]*(bak|old|[\d.]+)?/)|(\w*admin\w*\.\w+)",re.I),# 3. 连续重复字符文件re.compile("/(\w)\\1{1,4}\.(php|zip|rar|tar|gz|tgz|bz2|7z)(\?|&|\s|$)",re.I),# 4. 敏感路径re.compile("((etc/(passwd|shadow|(sys)?(\w*\.)conf(ig)?|\.?ssh|httpd|apache|bashrc|issue|termcap|inputrc|group))|web-inf|usr/local|(var/(lib|logs?|cahces?|apache2?)))",re.I),# 5. 连续数字文件re.compile("(/\d{1,5}\.(php|zip|rar|tar|gz|tgz|bz2|7z))(\?|&|\s|$)")]

2.2 正则优化

  1. 正则顺序优化:按照Sensitive类的定义,当url匹配到关键内容后即返回匹配内容,跳出正则过滤的循环。因此,为了进一步降低性能的消耗,将生产环境中命中频率最高的正则放在最前面,命中率低的正则放在靠后位置。

  2. 单条正则调优:由于正则匹配搜索的优先级为由左向右,因此将生产环境中命中频率最高的放在左边,最低的放在最右边。

2.3 准确率和召回率评估

评估方式:模型部署在SSMP平台,按每分钟进行聚合,并将检测到的扫描器数据作为Log日志打印。根据Yarn日志输出的扫描器IP和检测到的请求时间在云迹进行抽样验证。

3. 统计特征ML模型

扫描器请求和正常请求之间除了文本特征以外,在状态码、url长度、所携带ua的混乱度及访问域名的混乱度等也存在一定差异性。因此提取命中关键词次数及上述特征,结合WAF正常日志和规则检测到的扫描器日志形成黑白样本,进一步训练ML模型。

3.1 特征提取

  • 关键词提取
    结合网上常见的集中扫描器提取敏感内容字典,并结合规则模型识别的扫描器日志加以补充,组成关键词库。进一步随机提取全网流量作为白样本对扫描器关键词库进行匹配,并将白样本中大量存在的关键词剔除,最终关键词如下:

3.2 特征工程

除了关键词系数特征,同时还分别提取了请求次数、敏感词个数、敏感词威胁系数、UA混乱度、域名换乱度、状态码占比等特征进行示范。

class ScannerFeatures(object):def __init__(self):super(ScannerFeatures, self).__init__()self.wspatt = re.compile("/(\w)\\1{,4}\.(php|zip|rar|tar|gz|tgz|bz2|7z)(\?|&|\s|$)")self.nbpatt = re.compile("(/\d{1,5}\.(php|zip|rar|tar|gz|tgz|bz2|7z))(\?|&|\s|$)")self.adminpatt = re.compile(r'(/_*(sql|my(sql)?|php|db|sha)[+-._\d]*(my)?admins?[+-._]*(bak|old|[\d.]+)?/)|(\w*admin\w*\.\w+)', re.I)self.wordindex = eval(open('wordindex.txt', 'r').read())def statusRate(self, arr, statu):"""计算状态码占比"""return arr.count(statu) / len(arr)def GiniArr(self, arr):"""计算元素Gini系数"""D = dict(zip(*np.unique(arr, return_counts=True)))arr = [_ for _ in D.values()]n = sum(arr)g = 0for i in arr:g += (i / n) ** 2return 1 - gdef feature(self, data):"""输入Web日志Datafream数据,输出每个IP聚合后的特征向量"""X = np.zeros(len(self.wordindex))for url in list(data['url']):url = self.wspatt.subn(' wsfile ', url)[0].lower()url = self.nbpatt.subn(' nbfile ', url)[0]url = re.subn('\d+', '', url)[0]for kw in re.split('[^a-z]', url):try:X[self.wordindex[kw]] += 1except:passX = [np.log(x + 1) for x in X[X != 0]]nums = len(X)r = np.sum(X)cont = len(data)giniHost = self.GiniArr(list(data['host']))giniUa = self.GiniArr(list(data['ua']))sr200 = self.statusRate(list(data['status']), 200)sr403 = self.statusRate(list(data['status']), 403)sr404 = self.statusRate(list(data['status']), 404)srOts = 1 - sr200 - sr403 - sr404result = np.array([cont, nums, r, giniUa, giniHost, sr200, sr403, sr404, srOts])return result

3.3 模型评估

对规则模型采集的黑样本及Web日志白样本进行逐个人为验证并打标,进而训练随机森林模型、和MLP模型分别用召回率、准确率和F1得分进行评估。模型在训练及表现良好,但测试集中可以看出模型过拟合验证,结构风险太高。无法满足生产环境真实业务场景需求。针对不同的模型通过降低树深度、前后剪植,调整惩罚系数等方式降低模型结构风险造成准确率和召回率降低,左右权衡后效果均未能达到满意效果。

  • 测试1

  • 测试2

4. 基于n-gram特征提取的MLP模型

4.1 模型训练和评估示范

对传统机器学习来说,特征提取是比较繁琐的,需要对业务场景的深入理解。在扫描器识别任务中,我们可以将单个用户连续发起的请求序列拼接到一起作为一个短文本,采取NLP中情感分析的思想,分别训练词向量和分类器模型对扫描器请求序列进行识别。训练过程中需要注意参数n-gram和max_features的调整,这里分别代表取词方式和特征维度。我们先取部分数据实验不同的n-gram参数和max_features参数进行模型训练,并对测试集数据进行评估效果。在保证模型测试集评分的基础上,max_features越小资源消耗越小。

# 训练词向量
max_features = 3000
seed = 123
countvectorizer = CountVectorizer(ngram_range=(2, 2), decode_error="ignore",min_df=1, analyzer="word",token_pattern='[\w-]+',max_features=max_features)
X = countvectorizer.fit_transform(sequence).toarray()
y = lables
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=seed)# 训练模型
mlp = MLPClassifier(solver="adam", alpha=1e-5, hidden_layer_sizes=(5, 2), random_state=seed)
mlp.fit(x_train, y_train)
joblib.dump(mlp, "model/scan_mlp.pkl", compress=3)# 将模型参数和偏置保存为np格式
np.save("../model/weights",mlp.coefs_)
np.save("../model/bias",mlp.intercepts_)

在实际训练中,从苏宁应用防火墙(SNWAF)日志中抽取了275019条正常访问序列作为正样本,同时通过SNWAF输出的扫描器IP列表提取出361504条扫描器IP的访问序列作为黑样本,对模型进行训练,取得了比规则模型和统计特征ML模型更好的效果。该方法有更好的成长性,可以随着高质量训练数据的增长进行优化迭代,同时缺点是模型结构更加复杂,资源消耗较大。

4.2 模型工程化部署

由于需要实时对海量访问日志进行监控,我们需要将模型部署到分布式大数据计算平台。在实际的代码工程化部署过程中,可能会出现训练模型的环境与分布式环境模块版本不一致或缺少模块导致的模型加载失败问题。针对上述问题,我们采取了一些办法:

  1. 抽取countvectorizer模型的字典向量,手动构建词向量转换函数
  2. 重写MLP模型预测代码,将模型预测逻辑函数化
# 词向量转换
def urls2vec(self, url):N = len(self.max_features)X = np.zeros(N)for word in self.url_split(url):X[self.wordindex[word]] += 1return X# MLP模型预测逻辑函数化
class MLPPredict(object):"""输入向量给出识别结果"""def __init__(self, weights, bias):super(MLPPredict, self).__init__()self.weights = weightsself.bias = biasself.layers = [5, 2]self.n_layers = len(self.layers) + 2self.n_outputs = 1@staticmethoddef relu(x):np.clip(x, 0, np.finfo(x.dtype).max, out=x)return xdef forward_pass(self, activations):for i in range(self.n_layers - 1):activations[i + 1] = np.dot(activations[i],self.weights[i])activations[i + 1] += self.bias[i]# For the hidden layersif (i + 1) != (self.n_layers - 1):activations[i + 1] = self.relu(activations[i + 1])activations[i + 1] = self.logistic(activations[i + 1])return activationsdef predict(self, x):layer_units = [x.shape[1]] + self.layers + \[self.n_outputs]activations = [x]for i in range(self.n_layers - 1):activations.append(np.empty((x.shape[0],layer_units[i + 1])))activations = self.forward_pass(activations)y_pred = activations[-1]return round(float(y_pred[0][0]))

通过本地测试我们发现,采取上述方式与加载模型的输出结果一直,并且预测效率更高。

我们通过创建pyspark-streaming任务,实时消费WAF访问日志对每批次用户的访问日志进行向量化转化后输入预测模型,从而实现扫描器的实时监控,并将检测到的扫描器IP进行告警或根据配置实施访问限制。

5. 总结

本文对各类web扫描特特征进行了梳理和总结,并展示了利用规则模型和统计特征ML模型对扫描器的识别效果。

其中规则模型有天然的优势,所见即所得,可信度高可解释性强,同时满足奥朗姆剃刀简单高效原则,然而只对已知的扫描类型有效,合理的阈值设计非常重要,需要结合实际业务流量来精准分析;基于统计特征的机器学习识别模型的特征提取相对简单,只抽取了少量数据集进行训练,表达能力有限,不能够充分学习到正常请求行为和扫描器行为的区别,有兴趣的同学可以在此基础上进行更加精细化的特征提取以达到识别率的提升;基于n-gram特征提取的MLP模型具备更好的成长性,可以随着高质量训练样本数据的增加进行优化迭代,同时缺点是相对前两种方式资源消耗略大。

在实际的生产应用中,我们选择AI模型的落地,需要根据企业的数据规模、资源情况和需求标准来选择适合自己场景的模型和方式,最适合的才是最好的。

img

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/292889.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

将一个压缩文件分成多个压缩文件;RAR文件分卷

有时候需要上传压缩文件&#xff0c;但是限制了单个文件的大小&#xff0c;那我们怎么才能将一个比较大的压缩文件分割成多个压缩文件&#xff0c;从而符合要求的进行文件的上传呢&#xff1f;这里小编告诉你一个技巧。 工具/原料 电脑 winrar&#xff08;一般电脑都自带了&…

python画相关性可视化图_Python可视化很简单,一文教你绘制饼图、极线图和气泡图...

matplotlib库作为Python数据化可视化的最经典和最常用库&#xff0c;掌握了它就相当于学会了Python的数据化可视化&#xff0c;上次呢&#xff0c;已经和大家聊了关于柱状图、条形图和直方图相关的东东&#xff0c;相信大家已经掌握了哈&#xff0c;那今天呢&#xff0c;咱们再…

图像处理技术(二)滤波去噪

在图像处理领域中&#xff0c;在真正的应用过程前&#xff0c;通常需要对图像进行预先处理&#xff0c;达到去除干扰项的目的。滤波去噪就是其中的一项图像预处理工作。在.NET下常用OpenCV进行图像处理工作,常用的.NET下的OpenCV库有Emgu CV和OpenCVSharp。EmguCV是.NET平台下对…

iOS开发之Runtime关联属性

2019独角兽企业重金招聘Python工程师标准>>> 首先&#xff0c;推荐给大家一个非常好用的一个网站&#xff1a; 非盈利无广告开发者专用网址导航&#xff1a;http://www.dev666.com/ API介绍 我们先看看Runtime提供的关联API&#xff0c;只有这三个API&#xff0c;使…

DecisionTree决策树算法及参数详解+实例+graphviz生成决策树

DecisionTree决策树大全 原文&#xff1a;http://ihoge.cn/2018/DecisionTree.html 利用信息墒判定先对那个特征进行分裂 信息墒是衡量信息不确定性的指标&#xff0c;信息墒公式&#xff1a; H(X)−∑x∈XP(x)log2P(x)其中P(x)表示事件x出现的概率。回到决策树的构建问题上…

穿皮裤放屁,裤子会鼓吗?真相看这里!

1 拉莫斯&#xff1a;没事儿&#xff0c;打今儿起我管你叫哥&#xff0c;你管我叫爸&#xff0c;咱俩各论各的。▼2 妈妈都是为了你好▼3 秃头女孩最后的倔强▼4 新浪OS&#xff1a;呼~太紧张了&#xff0c;放松下▼5 这什么鬼玩意儿&#xff1f;▼6 这到底是爱老婆&…

史上最强物理科普

全世界只有3.14 % 的人关注了爆炸吧知识一沙见世界 一花窥天堂手心握无限 须臾纳永恒杨振宁曾说读上面的四句诗可以感受到物理的美但物理的美不止于此物理还有一种庄严美一种神秘美一种初窥宇宙奥秘的畏惧美物理就是如此的迷人任何语言在它的面前都很贫瘠数学让人摆脱了愚昧而…

直方图python高度_python – 子图中直方图的动画

normed 直方图的True参数使直方图绘制分布的密度.从the documentation开始&#xff1a; normed : boolean, optional If True, the first element of the return tuple will be the counts normalized to form a probability density, i.e., n/(len(x)dbin), i.e., the integra…

Kubernetes:全面了解 Deployment

本文为作者的 Kubernetes 系列电子书的一部分&#xff0c;电子书已经开源&#xff0c;欢迎关注&#xff0c;电子书浏览地址&#xff1a;https://k8s.whuanle.cn【适合国内访问】https://ek8s.whuanle.cn 【gitbook】Deployment 是 Kubernetes 提供的一种自我修复机制来解决机器…

史上最冤!美国原子弹之父被骂了9年!最后他上台领奖,竟一把推开了总统.........

全世界只有3.14 % 的人关注了爆炸吧知识原子裂变不及人心善变“漫天奇光异彩&#xff0c;犹如圣灵逞威&#xff0c;祇有千只太阳&#xff0c;始能与它争辉。”1945年7月15日&#xff0c;奥本海默注视着远处的蘑菇云&#xff0c;想起了《摩诃婆罗多经&#xff1a;福者之歌》中的…

spring 基于java的配置

2019独角兽企业重金招聘Python工程师标准>>> 7.10 Classpath scanning and managed componets 文档地址: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-classpath-scanning 本章中大部分例子是用xml来指定配置元数据,以…

WPF 实现3D翻转倒计时控件~

WPF开发者QQ群&#xff1a; 340500857由于微信群人数太多入群请添加小编微信号yanjinhuawechat 或 W_Feng_aiQ 邀请入群需备注WPF开发者 PS&#xff1a;有更好的方式欢迎推荐。接着上一篇倒计时控件01—代码如下一、创建 NumberCardControl.xaml代码如下。<UserControl x:Cl…

Android之Android studio基本调试和快捷键

第一种调试方法: 如果APP是单进程,直接debug运行,如下图 第二种调试方法: 第二种就是调试当前已经处于运行状态下的App,这也是我们用的更多的一种调试手段,即 Attach debugger to Android process 。点击运行按钮右侧第三个按钮,弹出 Choose Process 窗口,选择对应的进…

Windows 2008 R2安装DHCP服务器问题及解决方法

错误一&#xff1a;0x80074E6F 指定的服务器已在目录服务中造成此错误的原因是DHCP服务器没有正常卸载&#xff0c;第二次安装就会报如下图错误解决方法1.卸载DHCP服务器2.重启服务器3.打开adsiedit.msc4.如下图展开到 CNNetServices5.删除CNYour ServerName6.重新安装DHCP服务…

免费动态域名解析

DDNS 顾名思义就是动态域名解析&#xff0c;让域名绑定在动态 IP 上&#xff0c;比如拨号上网的 ADSL 用户。国内的 DDNS 服务有花生壳和 3322.org 这种提供商&#xff0c;我一直在用花生壳的免费 DDNS&#xff0c;可是近期情况非常糟糕&#xff0c;我到北京以来&#xff0c;就…

2021 年 CNCF 和开源速度的年终报告

深入了解开发速度最快的项目&#xff0c;可以很好地表明哪些领域正在起飞&#xff0c;哪些平台可能在未来几个月和几年内取得成功。如何评估一个项目的活跃度&#xff0c;通常从这几个方面, commits, contributions, issues 和 pull requests&#xff0c;而使用气泡图是一种很巧…

清华姚班毕业生不配自信?张昆玮在豆瓣征女友,却被网友群嘲......

全世界只有3.14 % 的人关注了爆炸吧知识不要看脸好好说话没想到&#xff0c;清华也有被瞧不起的一天。上周&#xff0c;山西某网友在D瓣上发布了一则征友贴&#xff1a;总结下来&#xff0c;就是一句话&#xff1a;俺&#xff0c;一介俗人&#xff0c;二本教师&#xff0c;兼职…

python自带的函数有哪些_为什么说 Python 内置函数并不是万能的?

在Python猫的上一篇文章中&#xff0c;我们对比了两种创建列表的方法&#xff0c;即字面量用法 [] 与内置类型用法 list()&#xff0c;进而分析出它们在运行速度上的差异。在分析为什么 list() 会更慢的时候&#xff0c;文中说到它需要经过名称查找与函数调用两个步骤&#xff…