网络安全 - DOS
1.1.1 摘要
最近网络安全成了一个焦点,除了国内明文密码的安全事件,还有一件事是影响比较大的——Hash Collision DoS(通过Hash碰撞进行的拒绝式服务攻击),有恶意的人会通过这个安全漏洞让你的服务器运行巨慢无比,那他们是通过什么手段让服务器巨慢无比呢?我们如何防范DoS攻击呢?本文将给出详细的介绍。
1.1.2 正文
在介绍Hash Collision DoS攻击之前,首先让我们复习一下哈希表(Hash table)。
哈希表(Hash table,也叫散列表),是根据关键码值(Key/Value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做哈希函数(它的好坏将关系到系统的性能),存放记录的数组叫做哈希表。
大家知道哈希函数在计算哈希值时不可以避免地会出现哈希冲突。
假设我们定义了一个哈希函数hash(),m代表未经哈希计算的原始键,而h是m经过哈希函数hash()计算后得出的哈希值。
现在我们对原始键m1和m2进行哈希计算就可以获取相应的哈希值分别为:hash(m1)和hash(m2)。
如果原始键m1=m2,那么将可能得到相同的哈希值,但是键m1!=m2也可能得到相同的哈希值,那么就发生了哈希冲突(Hash collision),在大多数的情况下,哈希冲突只能尽可能地减少,而无法完全避免。
当发生哈希冲突时,我们可以使用冲突解决方法解决冲突,而主要的哈希冲突解决方法如下:
开放地址法
再哈希法
链地址法
建立一个公共溢出区
当发生哈希冲突时,我们的确可以采用以上的方法解决哈希冲突,但我们能不能尽可能避免哈希冲突的出现呢?如果哈希冲突被减少到微乎其微,那么我们系统性能将得到很大提高,我们通过使用冲突几率更低的算法计算哈希值。
一般情况衡量一种算法的好坏是通过它的最优,一般和最差情况的时空复杂度来衡量算法好坏的。
在理想情况下,哈希表插入、查找和删除一个元素操作的时间复杂度都为O(1),那么插入、查找和删除n个元素的时间复杂度就为O(n),任何一个数据项可以在一个与哈希表长度无关的时间内计算出一个哈希值(Key),然后根据哈希值(Key)定位到哈希表中的一个槽中(术语bucket,表示哈希表中的一个位置)。最理想情况是我们在长度为n的哈希表中插入n个元素,而且经过哈希计算后它们的哈希值恰好均匀地分配到哈希表的每个槽中完全没有冲突,这的确太理想了。但这不符合实际情况,由于我们无法预知插入元素的个数,而且哈希表的长度也是有限的,所以说哈希冲突是无法避免的。
图1 哈希表时间复杂度
碰撞解决大体有两种思路,第一种策略是根据某种原则将被碰撞数据定为到其它槽中,例如开放地址法的线性探索,如果数据在插入时发生了碰撞,则顺序查找这个槽后面的槽,将其放入第一个没有被占有的槽中;第二种策略是每个槽不只是只能容纳一个数据项的位置,而是一个可容纳多个数据项的数据结构(例如链表或红黑树),所有碰撞的数据以某种数据结构的形式组织起来(线性探索:di = 1,2,3,…,m – 1)。
图2 开放地址法
不论使用哪种碰撞解决策略,都导致插入、查找和删除的操作的时间复杂度不再是O(1)。以查找为例:不能通过哈希值(Key)定位到槽就结束,还需要比较原始键(即未经过哈希的Key)是否相等,如果不相等,则使用与插入相同的算法继续查找,直到找到匹配的值或确认数据不在哈希表中。
.NET是使用第一种策略解决哈希冲突,它根据某种原则将碰撞数据定位到其他槽中。
而PHP是使用单链表存储碰撞的数据,因此实际上PHP哈希表的平均查找复杂度为O(L),其中L为桶链表的平均长度;而最坏复杂度为O(N),此时所有数据全部碰撞,哈希表退化成单链表。下图是PHP中正常哈希表和退化哈希表的示意图。
图3 正常哈希表
图4 退化哈希表
通过上图正常哈希表我们发现在正常情况下,哈希值分配的均匀冲突几率很低,而退化的哈希表中全部数据都在同一个槽上发生了冲突,这将导致数据插入、查找和删除的时间复杂度变为O(n2),由于时间复杂度提升了一个数量级,因此会消耗大量CPU资源,导致系统无法及时响应请求,从而达到拒绝服务攻击(DoS)的目的。
.NET中哈希表的实现
数据结构
在.NET中定义一个结构体bucket来表示槽,它只包含三个字段,具体代码如下:
/// <summary>
/// Defines hash bucket.
/// </summary>
private struct bucket
{/// <summary>/// The hask key./// </summary>public object key;/// <summary>/// The data value./// </summary>public object val;/// <summary>/// The key has hash collision./// </summary>public int hash_coll;
}
当发生冲突时,线性探索再散列在处理的过程中容易产生记录的二次聚集,而.NET通过使用再哈希和动态增加哈希表长度来减少再发生哈希冲突。
/// <summary>
/// Rehashes the specified newsize.
/// </summary>
/// <param name="newsize">The newsize.</param>
private void rehash(int newsize)
{this.occupancy = 0;// Creates a new bucket.Hashtable.bucket[] newBuckets = new Hashtable.bucket[newsize];for (int i = 0; i < this.buckets.Length; i++){Hashtable.bucket bucket = this.buckets[i];if ((bucket.key != null) && (bucket.key != this.buckets)){this.putEntry(newBuckets, bucket.key, bucket.val, bucket.hash_coll & 0x7fffffff);}}Thread.BeginCriticalRegion();this.isWriterInProgress = true;// Changes the bucket.this.buckets = newBuckets;this.loadsize = (int)(this.loadFactor * newsize);this.UpdateVersion();this.isWriterInProgress = false;Thread.EndCriticalRegion();
}
通过上面的rehash()方法我们知道当发生冲突时,.NET通过再哈希和增大哈希表的长度来避免再发生冲突。
哈希算法
现在让我们看看.NET使用什么哈希算法,查看Object.GetHashCode()方法,具体代码如下:
public virtual int GetHashCode()
{return InternalGetHashCode(this);
}
我们发现Object.GetHashCode()方法调用了另一个方法InternalGetHashCode(),我们进一步查看InternalGetHashCode()方法,发现它映射到CLR中的一个方法ObjectNative::GetHashCode,具体实现代码如下:
FCIMPL1(INT32, ObjectNative::GetHashCode, Object* obj) { CONTRACTL { THROWS; DISABLED(GC_NOTRIGGER); INJECT_FAULT(FCThrow(kOutOfMemoryException);); MODE_COOPERATIVE; SO_TOLERANT; } CONTRACTL_END; VALIDATEOBJECTREF(obj); DWORD idx = 0; if (obj == 0) return 0; OBJECTREF objRef(obj); HELPER_METHOD_FRAME_BEGIN_RET_1(objRef); // Set up a frame // Invokes another method to create hash code.idx = GetHashCodeEx(OBJECTREFToObject(objRef)); HELPER_METHOD_FRAME_END(); return idx;
}
FCIMPLEND
该方法的实现并不复杂,但我们很快就发现其实该方法里再调用GetHashCodeEx()方法,它才是具体的哈希算法的实现,这里就不做详细的介绍因为实现代码很长,如果大家想查看它的C++源代码请点这里。
现在主流编程语言都采用的哈希算法是DJB(DJBX33A),而.NET中的NameValueCollection.GetHashCode()方法就是使用DJB算法。
DJB的算法实现核心是通过给哈希值(Key)乘以33(即左移5位再加上哈希值)计算哈希值,接下来让我们看一下DJB算法的实现吧!
/// <summary>
/// Uses DJBX33X hash function to hash the specified value.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The hash string</returns>
public static uint DJBHash(string value)
{if (string.IsNullOrEmpty(value)){throw new ArgumentNullException("The hash value can't be empty.");}uint hash = 5381;for (int i = 0; i < value.Length; i++){// The value of ((hash << 5) + hash) the same as // the value of hash * 33.hash = ((hash << 5) + hash) + value[i];}}
我们看到DJB算法实现十分简单,但它却是十分优秀的哈希算法,它生成的哈希值冲突几率很低,接下来让我们看一下.NET中String.GetHashCode()方法的实现——DEK算法。
/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms
/// and data structures like a hash table.
/// </returns>
public override unsafe int GetHashCode()
{// Pins the heap address, so GC can't collect it.fixed (char* str = ((char*)this)){char* chPtr = str;int num = 0x15051505;int num2 = num;int* numPtr = (int*)chPtr;for (int i = this.Length; i > 0; i -= 4){// Uses DEK to generate hash code.num = (((num << 5) + num) + (num >> 0x1b)) ^ numPtr[0];if (i <= 2){break;}// Uses DEK to generate hash code.num2 = (((num2 << 5) + num2) + (num2 >> 0x1b)) ^ numPtr[1];numPtr += 2;}return (num + (num2 * 0x5d588b65));}
}
String类中重写了GetHashCode()方法,由于GetHashCode()会涉及到一些指针操作,所以把该方法定义为unsafe表示不安全上下文,也许有人会奇怪C#中还能像C/C++中的指针操作吗?我们要在C#中使用指针操作,这时fixed关键字终于派上用场了。fixed 关键字是用来pin住一个引用地址的,因为我们知道CLR的垃圾收集器会改变某些对象的地址,因此在改变地址之后指向那些对象的引用就要随之改变。这种改变是对于程序员来说是无意识的,因此在指针操作中是不允许的。否则,我们之前已经保留下的地址,在GC后就无法找到我们所需要的对象(fixed详细介绍请参考这里)。
哈希碰撞攻击
通过前面介绍.NET中GetHashCode()方法,现在我们对于其中的实现算法有了初步的了解,由于哈希冲突的原理就是针对具体的哈希算法来构造数据,使得所有数据都发生碰撞。
但如何构造数据呢?首先让我们看一个例子,假设我们往一个类型为NameValueCollection的对象中插入数据。
图5 插入数据
通过上图我们发现插入1000个数据只需88 ms,当插入2000个数据需时345 ms,随着插入数据规模的增大我们发现插入时间越来越长,哈希表的插入时间复杂度不是O(n)吗?大家肯定知道这是由于发生哈希冲突导致时间复杂度无法达到线性。
这里我们使用了一个简单方法构造冲突数据——蛮力法。(效率低)
由于蛮力法效率低,所以我们采用更加高效的方法中途相遇攻击(meet-in-the-middle attack)或等效子串(equivalent substrings)来构造冲突数据。
等效子串:
如果哈希函数具有这样的特性,当两个字符串的哈希值发生冲突,例如:hash(“string1”)=hash(“string2”),那么由这两个子串在同一位置上构成的字符串也发生哈希冲突,例如:hash(“prefixstring1postfix”)=hash(“prefixstring2postfix”)。
假设“EZ”和“FY”在哈希函数中发生冲突,那么字符串“EzEz”,“EzFY”,“FYEz”,“FYFY”两两之间也发生冲突。大家想查看使用等效子串的例子点这里。
中途相遇攻击:
如果在一个给定的哈希函数中不存在等效子串,那么蛮力法似乎是唯一的解决办法了。但我们前面介绍蛮力法效率低,明显的以32位为例这种方式命中目标的概率是1 /(2 ^ 32)。
现在我们只需计算16位哈希值,那么命中目标的概率是1/(2^16),这样命中几率大大的提高了,而且构造数据时间也缩短了。
我们使用等效子串方法把字符串分成两部分,前缀子串(长度为n)和后缀子串(长度为m),接着我们枚举前缀子串的哈希值,并且使得它们的哈希值相等。
现在我们通过异或运算使得枚举前缀子串的哈希值都相等,首先我们让前缀子串乘以1041204193再经过DJB33计算哈希值。也许有人会问为什么要乘以1041204193呢?
由于1041204193 * 33 = 34359738369
二进制值:00000000000000000000000000000000001(使用Int32)
我们知道1041204193 * 33 = 1,那么现在的前缀子串的哈希值只与它的字符相关,这将导致冲突几率增大了。
HashBack()方法的示意代码如下:
/// <summary>
/// The hash back function.
/// </summary>
/// <param name="tmp">The string need to hash back.</param>
/// <param name="end">The hash back value.</param>
/// <returns>The hash back string.</returns>
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
private static unsafe int HashBack(string tmp, int end)
{int hash = end;fixed (char* str = tmp){char* suffix = str;int length = tmp.Length;for (; length > 0; length -= 1){hash = (hash ^ suffix[length - 1]) * 1041204193;}return hash;}
}
我们看到HashBack()方法包含两个参数,一个是要计算哈希值的字符串,而另外一个就是最后发生冲突的哈希值。
接来下我们让实现DJB33哈希函数示意代码如下:
/// <summary>
/// The hash function with DJB33 algorithm.
/// </summary>
/// <param name="tmp">The string need to hash.</param>
/// <returns>The hash value.</returns>
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
private static unsafe int Hash(string tmp)
{int hash = 5381;fixed (char* str = tmp){char* p = str;int tmpLenght = tmp.Length;for (; tmpLenght > 0; tmpLenght -= 1){hash = ((hash << 5) + hash) ^ *p++;}return hash;}
}
现在我们完成了HashBack()和Hash()方法,首先我们使用HashBack()方法计算出前缀子串的哈希值,然后再使用Hash()方法找出和前缀子串发生冲突的子串,最后把前缀和后缀拼接起来就构成了冲突字符串了。
也许大家听起来有点别扭,那么让我们通过具体的例子来说明吧!
假设我们找到前缀“BIS”,而且HashBack(“NBJ”) = 147958270,然后我们通过暴力方法找出了和前缀有冲突的后缀Hash(“SKF0FTG”) = 147958270,接着我们把它们拼接起来计算Hash(“NBJ” + “SKF0FTG”) = 6888888,我们看到拼接起来的字符串计数出来的哈希值是我们事先已经指定好的,所以我们可以通过这种方法不断构造冲突数据。
接着我们使用以上的冲突数据进行插入测试,一开始运行插入数据CPU的消耗就开始变得大了,曾经一度消耗到100%那时机器根本动不了,所以无法截图。
图7 哈希冲突测试
防御
限制CPU时间
这是最简单的方法可以减少此类攻击的影响,它通过减少CPU请求时间将被允许参加。对于PHP可以设置max_input_time参数值;在IIS(ASP.NET)中,可以通过设置“关机时间限制”值(默认90s)。
限制POST请求参数个数
本次微软推出的安全性更新是通过限制 ASP.NET处理 HTTP POST 请求時最多只能接受1000个参数个。(补丁)
如果我们的Web应用程序需要接受超过1000个参数,可以通过设置WebConfig中MaxHttpCollectionKeys的值来修改最多限制数,具体设置如下:
<!--Setting Max Http post value-->
<appSettings><add key="aspnet:MaxHttpCollectionKeys" value="1001" />
</appSettings>
限制POST请求长度
使用随机的哈希算法
由于我们事先知道使用的哈希算法,所以构造冲突数据更加有针对性,但一旦才有随机哈希算法我们没有办法预知使用算法,所以冲突数据很难构造,但不幸的是许多主流的编程语言都是采用非随机哈希算法,除了Perl之外,像.NET,Java,Ruby,PHP和Python等都是采用非随机算法。
1.1.3 总结
本文通过引入哈希表,接着介绍哈希表的实现和发生哈希冲突时处理的方法,然后针对具体的哈希算法构造冲突数据(等效子串和中途相应),最后介绍该如何防御Hash Denial Of Service 攻击。
由于我们事先知道使用的哈希算法,所以构造冲突数据更加有针对性,所以通过使用随机哈希算法可以更加有效防御Hash Denial Of Service 攻击,估计许多语言将会重新设计它们的哈希函数。
相关文章:

网络安全 - DOS
1.1.1 摘要 最近网络安全成了一个焦点,除了国内明文密码的安全事件,还有一件事是影响比较大的——Hash Collision DoS(通过Hash碰撞进行的拒绝式服务攻击),有恶意的人会通过这个安全漏洞让你的服务器运行巨慢无比&…...

【强化学习】Stable-Baselines3学习笔记
【强化学习】Stable-Baselines3学习笔记 Stable-Baselines3是什么安装ExampleReinforcement Learning Tips and TricksVecEnv相关在stablebaselines中使用自定义环境 Stable-Baselines3是什么 Stable Baselines3(简称SB3)是一套基于PyTorch实现的强化学习…...
前端真实面试题自用
一、写在前面 笔者,经过计算机学硕考研的失败后,想谋求一份前端工作实在是太难了。一方面,确实曾经学习过的东西很久没有拾起,另一方面,对于前端面经还是记忆不深刻,特地写此贴记录笔者在真实前端面试中遇…...

vue3和springboot使用websocket通信
前端端口:9090 后端端口:8080 vue3 引入依赖: npm install sockjs-client stomp/stompjs vue页面 <template><div><h1>WebSocket 示例</h1><button click"sendMessage">发送消息</button>…...
JS 解构、数组扩展符和模板字符串的常见用法
文章目录 解构1. 对象解构2. 数组解构 数组扩展符模板字符串 解构 1. 对象解构 想把对象中的属性赋值给变量时, 需要一次一次的赋值,很麻烦。而对象解构, 就是把对象的结构拆解开, 然后把拆解后的属性自动赋值给匹配的变量。 (1) 对象属性赋值变量的传统写法&…...

低代码开源项目Joget的研究——Joget7社区版安装部署
大纲 环境准备安装必要软件配置Java配置JAVA_HOME配置Java软链安装三方库 获取源码配置MySql数据库创建用户创建数据库导入初始数据 配置数据库连接配置sessionFactory编译下载tomcat启动下载aspectjweaver移动jw.war文件编写脚本运行 测试参考资料 Joget,作为一款开…...
Golang 为什么没有注解?
Go 的哲学是:“少就是多,显式优于隐式。”注解虽然方便,但会违背 Go 追求简洁和清晰的设计理念。 什么是注解?为什么看起来很实用? 注解的定义:注解是一种特殊的元信息,用于修饰代码(如类、方法、字段等),让程序或工具在运行时或编译时解析和处理这些信息。例如: …...

Visual Studio Code(VS Code)配置C/C++环境
一、Visual Studio Code安装 Visual Studio Code,下文中简称为VS Code的详细安装方法请参考VSCode安装教程(超详细)-CSDN博客 二、MinGW编译器下载与配置 1、MinGW介绍 MinGW(Minimalist GNU for Windows)是一款用于Windows 平台的轻…...

LabVIEW软件开发的未来趋势
LabVIEW软件开发的未来趋势可以从以下几个方面来分析: 1. 与AI和机器学习的深度结合 趋势:LabVIEW正在向集成AI和机器学习方向发展,尤其是在数据处理、预测性维护和自动化控制领域。 原因:AI技术的普及使得实验和工业场景中的…...
Node.js 助力前端开发:自动化操作实战
前端开发中,重复性任务如新建文件、配置路由、生成组件等,往往耗时且容易出错。借助 Node.js 的强大能力,我们可以实现开发过程中的自动化操作,提高效率。 文章目录 自动生成 router 配置文件自动生成组件模板动态构建导航菜单自…...
HuggingFace peft LoRA 微调 LLaMA
1. 安装必要库 pip install transformers peft accelerate2. 加载 LLaMA 模型和分词器 从 Hugging Face Transformers 加载预训练的 LLaMA 模型和分词器。 from transformers import AutoModelForCausalLM, AutoTokenizer# 加载 LLaMA 模型和分词器 model_name "meta-…...
记-编译magisk_v22
1) 下载源码 git clone gitgitee.com:MayuriNFC/Magisk.git 使用国内镜像站 2) 切换标签: git checkout v22.0 3)下载/更新依赖 git submodule initgit sumodule update 4)下载对应ndk(自动下载出错了,用了手动下载), wget -c https://dl.google.com/android/reposito…...
前端登录业务
1.用户登录成功拿到token,放在请求拦截器的请求头中,调用户接口才可以获取到用户信息,存储到仓库中,以便其他组件使用用户信息 2.退出登录需要清空用户数据,以及本地存储,调退出登录接口告诉服务器当前toke…...

项目2路由交换
背景 某学校为满足日常教学生活需求,推动数字校园的建设,学校有办公楼和学生宿舍楼和服务器集群三块区域,请合理规划IP地址和VLAN,实现企业内部能够互联互通现要求外网能通过公网地址访问服务器集群,学生和老师能正常…...

易语言 OCR 文字识别
一.引言 文字识别,也称为光学字符识别(Optical Character Recognition, OCR),是一种将不同形式的文档(如扫描的纸质文档、PDF文件或数字相机拍摄的图片)中的文字转换成可编辑和可搜索的数据的技术。随着技…...
云手机+YouTube:改变通信世界的划时代技术
随着科技的不断进步,手机作为人们生活中不可或缺的工具,也在不断地更新换代。近年来,一个名为“油管云手机”的全新产品正在引起广泛的关注和讨论。作为一个运用最新科技实现的新型手机,它在通信领域带来了全新的体验和革命性的变…...

C++-----------映射
探索 C 中的映射与查找表 在 C 编程中,映射(Map)和查找表(Lookup Table)是非常重要的数据结构,它们能够高效地存储和检索数据,帮助我们解决各种实际问题。今天,我们就来深入探讨一下…...

清空DNS 缓存
如果遇到修改了host文件,但是IP和域名的映射有问题的情况,可以尝试刷新DNS缓存。 ipconfig/flushdns win建加R建,然后输入cmd,然后回车 然后回车,或者点击确定按钮。 出现如下所示标识清空DNS 缓存成功。...

计算机网络习题( 第3章 物理层 第4章 数据链路层 )
第3章 物理层 一、单选题 1、下列选项中,不属于物理层接口规范定义范畴的是( )。 A、 接口形状 B、 引脚功能 C、 传输媒体 D、 信号电平 正确答案: C 2、在物理层接口特性中,用于描述完成每种功能的事件发…...

UE5 崩溃问题汇总!!!
Using bundled DotNet SDK version: 6.0.302 ERROR: UnrealBuildTool.dll not found in "..\..\Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll" 在你遇到这种极奇崩溃的BUG ,难以解决的时候。 尝试了N种方法,都不行的解决方法。…...

网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...

微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...