https一定是安全的吗
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了https一定是安全的吗相关的知识,希望对你有一定的参考价值。
https不一定全是安全的,一些网站会使用自签名证书。自签名证书是指不受信任的任意机构或个人,使用工具自己签发的SSL证书。不是从公共证书机构(CA)那里申请来的证书,没有第三方监督审核,不受浏览器和操作系统信任,常被用于伪造证书进行中间人攻击,劫持SSL加密流量。
使用自签名证书的危害:
危害一:自签SSL证书最容易被假冒和伪造,被欺诈网站利用
自签SSL证书是可以随意签发的,不受任何监管,您可以自己签发,别人也可以自己签发。如果您的网站使用自签SSL证书,那黑客也可以伪造一张一模一样的自签证书,用在钓鱼网站上,伪造出有一样证书的假冒网银网站!
危害二:部署自签SSL证书的网站,浏览器会持续弹出警告
自签SSL证书是不受浏览器信任的,用户访问部署了自签SSL证书的网站时,浏览器会持续弹出安全警告,极大影响用户体验。
危害三:自签SSL证书最容易受到SSL中间人攻击
用户访问部署了自签SSL证书的网站,遇到浏览器警告提示时,网站通常会告知用户点击“继续浏览”,用户逐渐养成了忽略浏览器警告提示的习惯,这就给了中间人攻击可乘之机,使网站更容易受到中间人攻击。
典型的SSL中间人攻击就是中间人与用户或服务器在同一个局域网,中间人可以截获用户的数据包,包括SSL数据包,并做一个假的服务器SSL证书与用户通信,从而截获用户输入的机密信息。当网站被假的SSL证书替换时,浏览器会警告用户此证书不受信任,需要用户确认是否信任此证书,用户习惯性点击“继续浏览”,中间人攻击轻而易举的实现了。
所以说,选择SSL证书还是要选择国际知名的SSL证书,一些证书机构并没有受到国际的认证,颁发的证书并不能得到所有浏览器的信任。 参考技术A 您好!
HTTPS在完全加密过程是一定安全的,但比如您本地的网络被促改指向了一个不安全网站,然而这个网站可能也是一个假的HTTPS,这种情况下是不安全的。那么在HTTPS情况下,比如EV SSL证书,采取的地址栏直接提示企业名称,比如银行EV,他们可以确保是一定安全的。普通的DV SSL证书用于数据的加密协议传输,不足以识别真假网站的功能,所以对于数据协议上的传输,防劫持等是没有问题的。 参考技术B https 数据是通过加密传输的,只能说相对安全。并不能保证绝对安全。 参考技术C 不是的。
不一定是安全的。 参考技术D 你好!
HTTPS是安全的。当我们打开网站的时候,是需要和服务器进行通信的,那么HTTPS能够保证在通信时数据传输是安全的。如果我们打开一个网页,在网址的前面有标明“https”的话,那么就说明这个网站有证书并且有进行加密的操作。
ThreadLocalRandom 是线程安全的吗?
来源:https://zhenbianshu.github.io
前言
最近在写一些业务代码时遇到一个需要产生随机数的场景,这时自然想到 jdk 包里的 Random
类。
但出于对性能的极致追求,就考虑使用 ThreadLocalRandom
类进行优化,在查看 ThreadLocalRandom 实现的过程中,又追了下 Unsafe
有部分代码,整个流程下来,学到了不少东西,也通过搜索和提问解决了很多疑惑,于是总结成本文。
Random 的性能问题
使用 Random 类时,为了避免重复创建的开销,我们一般将实例化好的 Random 对象设置为我们所使用服务对象的属性或静态属性,这在线程竞争不激烈的情况下没有问题,但在一个高并发的 web 服务内,使用同一个 Random 对象可能会导致线程阻塞。
Random 的随机原理是对一个”随机种子”进行固定的算术和位运算,得到随机结果,再使用这个结果作为下一次随机的种子。在解决线程安全问题时,Random 使用 CAS 更新下一次随机的种子,可以想到,如果多个线程同时使用这个对象,就肯定会有一些线程执行 CAS 连续失败,进而导致线程阻塞。
ThreadLocalRandom
jdk 的开发者自然考虑到了这个问题,在 concurrent 包内添加了 ThreadLocalRandom
类,第一次看到这个类名,我以为它是通过 ThreadLocal 实现的,进而想到恐怖的内存泄漏问题,但点进源码却没有 ThreadLocal 的影子,而是存在着大量 Unsafe 相关的代码。
我们来看一下它的核心代码:
UNSAFE.putLong(t = Thread.currentThread(), SEED, r = UNSAFE.getLong(t, SEED) + GAMMA);
翻译成更直观的 Java 代码就像:
Thread t = Thread.currentThread();
long r = UNSAFE.getLong(t, SEED) + GAMMA;
UNSAFE.putLong(t, SEED, r);
看上去非常眼熟,像我们平常往 Map 里 get/set 一样,以 Thread.currentThread()
获取到的当前对象里 key,以 SEED 随机种子作为 value。
但是以对象作为 key 是可能会造成内存泄漏的啊,由于 Thread 对象可能会大量创建,在回收时不 remove Map 里的 value 时会导致 Map 越来越大,最后内存溢出。
Unsafe
功能
不过再仔细看 ThreadLocalRandom 类的核心代码,发现并不是简单的 Map 操作,它的 getLong() 方法需要传入两个参数,而 putLong() 方法需要三个参数,查看源码发现它们都是 native 方法,我们看不到具体的实现。两个方法签名分别是:
public native long getLong(Object var1, long var2);
public native void putLong(Object var1, long var2, long var4);
虽然看不到具体实现,但我们可以查得到它们的功能,下面是两个方法的功能介绍:
- putLong(object, offset, value) 可以将 object 对象内存地址偏移 offset 后的位置后四个字节设置为 value。
- getLong(object, offset) 会从 object 对象内存地址偏移 offset 后的位置读取四个字节作为 long 型返回。
不安全性
作为 Unsafe 类内的方法,它也透露着一股 “Unsafe” 的气息,具体表现就是可以直接操作内存,而不做任何安全校验,如果有问题,则会在运行时抛出 Fatal Error
,导致整个虚拟机的退出。
在我们的常识里,get 方法是最容易抛异常的地方,比如空指针、类型转换等,但 Unsafe.getLong() 方法是个非常安全的方法,它从某个内存位置开始读取四个字节,而不管这四个字节是什么内容,总能成功转成 long 型,至于这个 long 型结果是不是跟业务匹配就是另一回事了。而 set 方法也是比较安全的,它把某个内存位置之后的四个字节覆盖成一个 long 型的值,也几乎不会出错。
那么这两个方法”不安全”在哪呢?
它们的不安全并不是在这两个方法执行期间报错,而是未经保护地改变内存,会引起别的方法在使用这一段内存时报错。
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
// Unsafe 设置了构造方法私有,getUnsafe 获取实例方法包私有,在包外只能通过反射获取
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
// Test 类是一个随手写的测试类,只有一个 String 类型的测试类
Test test = new Test();
test.ttt = "12345";
unsafe.putLong(test, 12L, 2333L);
System.out.println(test.value);
}
运行上面的代码会得到一个 fatal error,报错信息为 “A fatal error has been detected by the Java Runtime Environment: … Process finished with exit code 134 (interrupted by signal 6: SIGABRT)”。
可以从报错信息中看到虚拟机因为这个 fatal error abort 退出了,原因也很简单,我使用 unsafe 将 Test 类 value 属性的位置设置成了 long 型值 2333,而当我使用 value 属性时,虚拟机会将这一块内存解析为 String 对象,原 String 对象对象头的结构被打乱了,解析对象失败抛出了错误,更严重的问题是报错信息中没有类名行号等信息,在复杂项目中排查这种问题真如同大海捞针。
不过 Unsafe 的其他方法可不一定像这一对方法一样,使用他们时可能需要注意另外的安全问题,之后有遇到再说。
ThreadLocalRandom 的实现
那么 ThreadLocalRandom 是不是安全的呢,再回过头来看一下它的实现。
ThreadLocalRandom 的实现需要 Thread 对象的配合,在 Thread 对象内存在着一个属性 threadLocalRandomSeed
,它保存着这个线程专属的随机种子,而这个属性在 Thread 对象的 offset,是在 ThreadLocalRandom 类加载时就确定了的,具体方法是 SEED = UNSAFE.objectFieldOffset(Thread.class.getDeclaredField("threadLocalRandomSeed"));
我们知道一个对象所占用的内存大小在类被加载后就确定了的,所以使用 Unsafe.objectFieldOffset(class, fieldName)
可以获取到某个属性在类中偏移量,而在找对了偏移量,又能确定数据类型时,使用 ThreadLocalRandom 就是很安全的。
疑问
在查找这些问题的过程中,我也产生了两个疑问点。
使用场景
首先就是 ThreadLocalRandom 为什么非要使用 Unsafe 来修改 Thread 对象内的随机种子呢,在 Thread 对象内添加 get/set 方法不是更方便吗?
stackOverFlow 上有人跟我同样的疑问:
https://stackoverflow.com/que...
被采纳的答案里解释说,对 jdk 开发者来说 Unsafe 和 get/set 方法都像普通的工具,具体使用哪一个并没有一个准则。
这个答案并没有说服我,于是我另开了一个问题,里面的一个评论我比较认同,大意是 ThreadLocalRandom 和 Thread 不在同一个包下,如果添加 get/set 方法的话,get/set 方法必须设置为 public,这就有违了类的封闭性原则。
内存布局
另一个疑问是我看到 Unsafe.objectFieldOffset 可以获取到属性在对象内存的偏移量后,自己在 IDEA 里使用 main 方法试了上文中提到的 Test 类,发现 Test 类的唯一一个属性 value 相对对象内存的偏移量是 12,于是比较疑惑这 12 个字节的组成。
我们知道,Java 对象的对象头是放在 Java 对象的内存起始处的,而一个对象的 MarkWord 在对象头的起始处,在 32 位系统中,它占用 4 个字节,而在 64 位系统中它占用 8 个字节,我使用的是 64 位系统,这毫无疑问会占用 8 个字节的偏移量。
紧跟 MarkWord 的应该是 Test 类的类指针和数组对象的长度,数组长度是 4 字节,但 Test 类并非数组,也没有其他属性,数据长度可以排除,但在 64 位系统下指针也应该是 8 字节的啊,为什么只占用了 4 个字节呢?
唯一的可能性是虚拟机启用了指针压缩,指针压缩只能在 64 位系统内启用,启用后指针类型只需要占用 4 个字节,但我并没有显示指定过使用指针压缩。查了一下,原来在 1.8 以后指针压缩是默认开启的,在启用时使用 -XX:-UseCompressedOops
参数后,value 的偏移量变成了 16。
小结
在写代码时还是要多注意查看依赖库的具体实现,不然可能踩到意想不到的坑,而且多看看并没有坏处,仔细研究一下还能学到更多。
近期热文推荐:
1.600+ 道 Java面试题及答案整理(2021最新版)
2.终于靠开源项目弄到 IntelliJ IDEA 激活码了,真香!
3.阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!
4.Spring Cloud 2020.0.0 正式发布,全新颠覆性版本!
5.《Java开发手册(嵩山版)》最新发布,速速下载!
觉得不错,别忘了随手点赞+转发哦!
以上是关于https一定是安全的吗的主要内容,如果未能解决你的问题,请参考以下文章