(八)netty的SSL renegotiation攻击漏洞
为了满足安全规范,从http改造成https(见(四)启用HTTPS),然而启用https后就可以高枕无忧了吗?绿盟告诉你:当然不,TLS Client-initiated 重协商攻击(CVE-2011-1473)了解一下。
1. 漏洞
报告是这样的:
详细描述 该漏洞存在于SSL renegotiation的过程中。对于使用SSL重协商功能的服务都会受其影响。特别的,renegotiation被用于浏览器到服务器之间的验证。虽然目前可以在不启用renegotiation进程的情况下使用HTTPS,但很多服务器的默认设置均启用了renegotiation功能。该漏洞只需要一台普通电脑和DSL连接即可轻易攻破SSL服务器。而对于大型服务器集群来说,则需要20台电脑和120Kbps的网络连接即可实现。SSL是银行、网上电子邮件服务和其他用于服务器和用户之间保护私人数据并安全通信必不可少的功能。所以本次拒绝服务漏洞影响范围非常广危害非常大。
解决办法 使用SSL开启重协商的服务都会受该漏洞影响. Apache解决办法:
升级到Apache 2.2.15以后版本 IIS解决办法:
IIS .0启用SSL服务时,也会受影响。可以升级IIS .0到更高的版本。 Lighttpd解决办法:
建议升级到lighttpd 1.4.30或者更高,并设置ssl.disable-client-renegotiation = "enable"。
http://download.lighttpd.net/lighttpd/releases-1.4.x/ Nginx解决办法:
0.7.x升级到nginx 0.7.
0.8.x升级到 0.8. 以及更高版本。
http://nginx.org/en/download.html Tomcat解决办法:
、使用NIO connector代替BIO connector,因为NIO不支持重协商,参考如下配置:
<Connector protocol="org.apache.coyote.http11.Http11NioProtocol">
(可能会影响Tomcat性能);
、配置Nginx反向代理,在Nginx中修复OpenSSL相关问题。
参考链接:
https://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html
https://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html
http://tomcat.apache.org/security-7.html#Not_a_vulnerability_in_Tomcat
https://tomcat.apache.org/tomcat-6.0-doc/config/http.html#Connector_Comparison Squid解决办法:
升级到3..24以及以后版本
http://www.squid-cache.org/Versions/ 其它服务解决方案请联系各应用厂商确认关闭重协商的方法。
然而我的http server用的是netty(netty既支持jdk ssl,也支持open ssl,open ssl的安全性和性能都比jdk ssl来的高,可以参考博文)。
解决方案中并无想要的信息,仅有一个用nginx增加反向代理,这种方式并无法让我感到满意,网上搜了一堆信息,但并没有找到想要的答案,因此只能从源码找起了。
2. 找http server
方式是直接从启动入口,通过find usages往上找。
@Override
public void start() throws WebServerException {
if (this.nettyContext == null) {
try {
this.nettyContext = startHttpServer();
}
catch (Exception ex) {
if (findBindException(ex) != null) {
SocketAddress address = this.httpServer.options().getAddress();
if (address instanceof InetSocketAddress) {
throw new PortInUseException(
((InetSocketAddress) address).getPort());
}
}
throw new WebServerException("Unable to start Netty", ex);
}
NettyWebServer.logger.info("Netty started on port(s): " + getPort());
startDaemonAwaitThread(this.nettyContext);
}
}
NettyWebServer
@Override
public WebServer getWebServer(HttpHandler httpHandler) {
HttpServer httpServer = createHttpServer();
ReactorHttpHandlerAdapter handlerAdapter = new ReactorHttpHandlerAdapter(
httpHandler);
return new NettyWebServer(httpServer, handlerAdapter, this.lifecycleTimeout);
}
NettyReactiveWebServerFactory
private HttpServer createHttpServer() {
        return HttpServer.builder().options((options) -> {
            options.listenAddress(getListenAddress());
            if (getSsl() != null && getSsl().isEnabled()) {
                SslServerCustomizer sslServerCustomizer = new SslServerCustomizer(
                        getSsl(), getSslStoreProvider());
                sslServerCustomizer.customize(options);
            }
            if (getCompression() != null && getCompression().getEnabled()) {
                CompressionCustomizer compressionCustomizer = new CompressionCustomizer(
                        getCompression());
                compressionCustomizer.customize(options);
            }
            applyCustomizers(options);
        }).build();
    }
NettyReactiveWebServerFactory
@Override
public void customize(HttpServerOptions.Builder builder) {
SslContextBuilder sslBuilder = SslContextBuilder
.forServer(getKeyManagerFactory(this.ssl, this.sslStoreProvider))
.trustManager(getTrustManagerFactory(this.ssl, this.sslStoreProvider));
if (this.ssl.getEnabledProtocols() != null) {
sslBuilder.protocols(this.ssl.getEnabledProtocols());
}
if (this.ssl.getCiphers() != null) {
sslBuilder = sslBuilder.ciphers(Arrays.asList(this.ssl.getCiphers()));
}
if (this.ssl.getClientAuth() == Ssl.ClientAuth.NEED) {
sslBuilder = sslBuilder.clientAuth(ClientAuth.REQUIRE);
}
else if (this.ssl.getClientAuth() == Ssl.ClientAuth.WANT) {
sslBuilder = sslBuilder.clientAuth(ClientAuth.OPTIONAL);
}
try {
builder.sslContext(sslBuilder.build());
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
SslServerCustomizer
public SslContext build() throws SSLException {
        if (forServer) {
            return SslContext.newServerContextInternal(provider, sslContextProvider, trustCertCollection,
                trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory,
                ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
                enableOcsp);
        } else {
            return SslContext.newClientContextInternal(provider, sslContextProvider, trustCertCollection,
                trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory,
                ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, enableOcsp);
        }
    }
SslContextBuilder
static SslContext newServerContextInternal(
SslProvider provider,
Provider sslContextProvider,
X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
boolean enableOcsp) throws SSLException { if (provider == null) {
provider = defaultServerProvider();
} switch (provider) {
case JDK:
if (enableOcsp) {
throw new IllegalArgumentException("OCSP is not supported with this SslProvider: " + provider);
}
return new JdkSslServerContext(sslContextProvider,
trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
clientAuth, protocols, startTls);
case OPENSSL:
verifyNullSslContextProvider(provider, sslContextProvider);
return new OpenSslServerContext(
trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
clientAuth, protocols, startTls, enableOcsp);
case OPENSSL_REFCNT:
verifyNullSslContextProvider(provider, sslContextProvider);
return new ReferenceCountedOpenSslServerContext(
trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
clientAuth, protocols, startTls, enableOcsp);
default:
throw new Error(provider.toString());
}
}
SslContext
找到这一步会发现provider为null,然后调用defaultServerProvider()方法里
private static SslProvider defaultProvider() {
        if (OpenSsl.isAvailable()) {
            return SslProvider.OPENSSL;
        } else {
            return SslProvider.JDK;
        }
    }
SslContext
/**
* Returns {@code true} if and only if
* <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support
* are available.
*/
public static boolean isAvailable() {
return UNAVAILABILITY_CAUSE == null;
}
OpenSsl
发现,源码会先找open ssl,如果找不到则启用jdk ssl。找open ssl的源码是这样的:
static {
        Throwable cause = null;
        if (SystemPropertyUtil.getBoolean("io.netty.handler.ssl.noOpenSsl", false)) {
            cause = new UnsupportedOperationException(
                    "OpenSSL was explicit disabled with -Dio.netty.handler.ssl.noOpenSsl=true");
            logger.debug(
                    "netty-tcnative explicit disabled; " +
                            OpenSslEngine.class.getSimpleName() + " will be unavailable.", cause);
        } else {
            // Test if netty-tcnative is in the classpath first.
            try {
                Class.forName("io.netty.internal.tcnative.SSL", false, OpenSsl.class.getClassLoader());
            } catch (ClassNotFoundException t) {
                cause = t;
                logger.debug(
                        "netty-tcnative not in the classpath; " +
                                OpenSslEngine.class.getSimpleName() + " will be unavailable.");
            }
            // If in the classpath, try to load the native library and initialize netty-tcnative.
            if (cause == null) {
                try {
                    // The JNI library was not already loaded. Load it now.
                    loadTcNative();
                } catch (Throwable t) {
                    cause = t;
                    logger.debug(
                            "Failed to load netty-tcnative; " +
                                    OpenSslEngine.class.getSimpleName() + " will be unavailable, unless the " +
                                    "application has already loaded the symbols by some other means. " +
                                    "See http://netty.io/wiki/forked-tomcat-native.html for more information.", t);
                }
                try {
                    String engine = SystemPropertyUtil.get("io.netty.handler.ssl.openssl.engine", null);
                    if (engine == null) {
                        logger.debug("Initialize netty-tcnative using engine: 'default'");
                    } else {
                        logger.debug("Initialize netty-tcnative using engine: '{}'", engine);
                    }
                    initializeTcNative(engine);
                    // The library was initialized successfully. If loading the library failed above,
                    // reset the cause now since it appears that the library was loaded by some other
                    // means.
                    cause = null;
                } catch (Throwable t) {
                    if (cause == null) {
                        cause = t;
                    }
                    logger.debug(
                            "Failed to initialize netty-tcnative; " +
                                    OpenSslEngine.class.getSimpleName() + " will be unavailable. " +
                                    "See http://netty.io/wiki/forked-tomcat-native.html for more information.", t);
                }
            }
        }
        UNAVAILABILITY_CAUSE = cause;
        if (cause == null) {
            logger.debug("netty-tcnative using native library: {}", SSL.versionString());
            final List<String> defaultCiphers = new ArrayList<String>();
            final Set<String> availableOpenSslCipherSuites = new LinkedHashSet<String>(128);
            boolean supportsKeyManagerFactory = false;
            boolean useKeyManagerFactory = false;
            boolean supportsHostNameValidation = false;
            try {
                final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER);
                long certBio = 0;
                SelfSignedCertificate cert = null;
                try {
                    SSLContext.setCipherSuite(sslCtx, "ALL");
                    final long ssl = SSL.newSSL(sslCtx, true);
                    try {
                        for (String c: SSL.getCiphers(ssl)) {
                            // Filter out bad input.
                            if (c == null || c.isEmpty() || availableOpenSslCipherSuites.contains(c)) {
                                continue;
                            }
                            availableOpenSslCipherSuites.add(c);
                        }
                        try {
                            SSL.setHostNameValidation(ssl, 0, "netty.io");
                            supportsHostNameValidation = true;
                        } catch (Throwable ignore) {
                            logger.debug("Hostname Verification not supported.");
                        }
                        try {
                            cert = new SelfSignedCertificate();
                            certBio = ReferenceCountedOpenSslContext.toBIO(ByteBufAllocator.DEFAULT, cert.cert());
                            SSL.setCertificateChainBio(ssl, certBio, false);
                            supportsKeyManagerFactory = true;
                            try {
                                useKeyManagerFactory = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                                    @Override
                                    public Boolean run() {
                                        return SystemPropertyUtil.getBoolean(
                                                "io.netty.handler.ssl.openssl.useKeyManagerFactory", true);
                                    }
                                });
                            } catch (Throwable ignore) {
                                logger.debug("Failed to get useKeyManagerFactory system property.");
                            }
                        } catch (Throwable ignore) {
                            logger.debug("KeyManagerFactory not supported.");
                        }
                    } finally {
                        SSL.freeSSL(ssl);
                        if (certBio != 0) {
                            SSL.freeBIO(certBio);
                        }
                        if (cert != null) {
                            cert.delete();
                        }
                    }
                } finally {
                    SSLContext.free(sslCtx);
                }
            } catch (Exception e) {
                logger.warn("Failed to get the list of available OpenSSL cipher suites.", e);
            }
            AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.unmodifiableSet(availableOpenSslCipherSuites);
            final Set<String> availableJavaCipherSuites = new LinkedHashSet<String>(
                    AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2);
            for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) {
                // Included converted but also openssl cipher name
                availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "TLS"));
                availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "SSL"));
            }
            addIfSupported(availableJavaCipherSuites, defaultCiphers, DEFAULT_CIPHER_SUITES);
            useFallbackCiphersIfDefaultIsEmpty(defaultCiphers, availableJavaCipherSuites);
            DEFAULT_CIPHERS = Collections.unmodifiableList(defaultCiphers);
            AVAILABLE_JAVA_CIPHER_SUITES = Collections.unmodifiableSet(availableJavaCipherSuites);
            final Set<String> availableCipherSuites = new LinkedHashSet<String>(
                    AVAILABLE_OPENSSL_CIPHER_SUITES.size() + AVAILABLE_JAVA_CIPHER_SUITES.size());
            availableCipherSuites.addAll(AVAILABLE_OPENSSL_CIPHER_SUITES);
            availableCipherSuites.addAll(AVAILABLE_JAVA_CIPHER_SUITES);
            AVAILABLE_CIPHER_SUITES = availableCipherSuites;
            SUPPORTS_KEYMANAGER_FACTORY = supportsKeyManagerFactory;
            SUPPORTS_HOSTNAME_VALIDATION = supportsHostNameValidation;
            USE_KEYMANAGER_FACTORY = useKeyManagerFactory;
            Set<String> protocols = new LinkedHashSet<String>(6);
            // Seems like there is no way to explicitly disable SSLv2Hello in openssl so it is always enabled
            protocols.add(PROTOCOL_SSL_V2_HELLO);
            if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV2, SSL.SSL_OP_NO_SSLv2)) {
                protocols.add(PROTOCOL_SSL_V2);
            }
            if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV3, SSL.SSL_OP_NO_SSLv3)) {
                protocols.add(PROTOCOL_SSL_V3);
            }
            if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1, SSL.SSL_OP_NO_TLSv1)) {
                protocols.add(PROTOCOL_TLS_V1);
            }
            if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_1, SSL.SSL_OP_NO_TLSv1_1)) {
                protocols.add(PROTOCOL_TLS_V1_1);
            }
            if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_OP_NO_TLSv1_2)) {
                protocols.add(PROTOCOL_TLS_V1_2);
            }
            SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet(protocols);
            SUPPORTS_OCSP = doesSupportOcsp();
            if (logger.isDebugEnabled()) {
                logger.debug("Supported protocols (OpenSSL): {} ", SUPPORTED_PROTOCOLS_SET);
                logger.debug("Default cipher suites (OpenSSL): {}", DEFAULT_CIPHERS);
            }
        } else {
            DEFAULT_CIPHERS = Collections.emptyList();
            AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet();
            AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet();
            AVAILABLE_CIPHER_SUITES = Collections.emptySet();
            SUPPORTS_KEYMANAGER_FACTORY = false;
            SUPPORTS_HOSTNAME_VALIDATION = false;
            USE_KEYMANAGER_FACTORY = false;
            SUPPORTED_PROTOCOLS_SET = Collections.emptySet();
            SUPPORTS_OCSP = false;
        }
    }
OpenSsl
最终发现是由于io.netty.internal.tcnative.SSL的类找不到。
直到现在ssl启动的顺序思路也比较清晰了,如果系统支持open ssl则启用open ssl,如果不支持则用jdk ssl。那么我们改造的方式也就相应的有2种:
1. 改造jdk ssl,禁用SSL renegotiation
2. 找到相对应的包,支持open ssl
个人倾向第二种,原因就是open ssl的性能和安全性比jdk ssl更加好。针对第一种,翻遍相关资料,均是对jdk1.8以下的,对jdk1.8以上的均没有说明(jdk1.8以下的参考这个)。
3. 支持open ssl
通过上面的源码,可以看到是io.netty.internal.tcnative.SSL找不到,那么我们就只要增加相对应的包就好了。
找了下maven仓库,有以下包可用:

在pom中增加对应的依赖
使用了netty-tcnative,会发现这种方式需要增加平台支持,不然就会报以下错误
Failed to load any of the given libraries: [netty_tcnative_windows_x86_64, netty_tcnative_x86_64, netty_tcnative]
载入的包越来越多
使用netty-tcnative-boringssl-static则没有任何问题(boringssl是google对openssl的一个fork,果然google强大)。
重启后用openssl s_client -connect进行连接,之后输入R进行验证:
[root@devlop gateway]# openssl s_client -connect localhost:443
CONNECTED(00000003)
depth=3 C = US, O = "The Go Daddy Group, Inc.", OU = Go Daddy Class 2 Certification Authority
verify return:1******中间省略******
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-SHA
Session-ID: 5C384430A5E50FB18848259D71396E94320454D6828439347F9791D43F32BC63
Session-ID-ctx:
Master-Key: 3D7FCF9A38CA624D9B22A79A05CCBBACDED4ED01DF5AD3E1CBF19BE9AEFD9CD08A6FECFC215ECEECF829C004C3D7F2F1
Key-Arg : None
Krb5 Principal: None
PSK identity: None
PSK identity hint: None
Start Time: 1547191344
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
===改造前===
R
RENEGOTIATING
depth=3 C = US, O = "The Go Daddy Group, Inc.", OU = Go Daddy Class 2 Certification Authority
verify return:1
depth=2 C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", CN = Go Daddy Root Certificate Authority - G2
verify return:1
depth=1 C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", OU = http://certs.godaddy.com/repository/, CN = Go Daddy Secure Certificate Authority - G2
verify return:1
depth=0 C = CN, L = \E6\9D\AD\E5\B7\9E\E5\B8\82, O = \E4\B8\AD\E7\A7\BB\EF\BC\88\E6\9D\AD\E5\B7\9E\EF\BC\89\E4\BF\A1\E6\81\AF\E6\8A\80\E6\9C\AF\E6\9C\89\E9\99\90\E5\85\AC\E5\8F\B8, CN = *****
verify return:1
read:errno=0
===改造后===
R RENEGOTIATING
140137592752032:error:1409444C:SSL routines:ssl3_read_bytes:tlsv1 alert no renegotiation:s3_pkt.c:1493:SSL alert number 100
140137592752032:error:1409E0E5:SSL routines:ssl3_write_bytes:ssl handshake failure:s3_pkt.c:659:
解决问题。
(八)netty的SSL renegotiation攻击漏洞的更多相关文章
- 【实战】SSL和TLS漏洞验证
		
工具下载:git clone https://github.com/drwetter/testssl.sh.git 实验环境:192.168.1.22(bee-box v1.6) 192.168.1. ...
 - SSL和TLS漏洞验证
		
工具下载:git clone https://github.com/drwetter/testssl.sh.git 实验环境:192.168.1.22(bee-box v1.6) 192.168.1. ...
 - 解决关键SSL安全问题和漏洞
		
解决关键SSL安全问题和漏洞 SSL(安全套接字层)逐渐被大家所重视,但是最不能忽视的也是SSL得漏洞,随着SSL技术的发展,新的漏洞也就出现了,下面小编就为大家介绍简单七步教你如何解决关键SSL安全 ...
 - Android安全之Https中间人攻击漏洞
		
Android安全之Https中间人攻击漏洞 0X01 概述 HTTPS,是一种网络安全传输协议,利用SSL/TLS来对数据包进行加密,以提供对网络服务器的身份认证,保护交换数据的隐私与完整性. ...
 - netty集成ssl完整参考指南(含完整源码)
		
虽然我们在内部rpc通信中使用的是基于认证和报文头加密的方式实现安全性,但是有些时候仍然需要使用SSL加密,可能是因为对接的三方系统需要,也可能是由于open的考虑.中午特地测了下netty下集成ss ...
 - Java Web项目漏洞:检测到目标URL存在http host头攻击漏洞解决办法
		
检测到目标URL存在http host头攻击漏洞 详细描述 为了方便的获得网站域名,开发人员一般依赖于HTTP Host header.例如,在php里用_SERVER["HTTP_HOST ...
 - 目标URL存在跨站漏洞和目标URL存在http host头攻击漏洞处理方案
		
若需要学习技术文档共享(请关注群公告的内容)/讨论问题 请入QQ群:668345923 :若无法入群,请在您浏览文章下方留言,至于答复,这个看情况了 目录 HTTP协议详解 引言 一.HTTP协议详解 ...
 - 检测到目标URL存在http host头攻击漏洞
		
检测到目标URL存在http host头攻击漏洞 1.引发安全问题的原因 为了方便的获得网站域名,开发人员一般依赖于HTTP Host header.例如,在php里用_SERVER["HT ...
 - Chargen UDP服务远程拒绝服务攻击漏洞修复教程
		
一.前置说明 chargen服务最初设计用于测试网络状态,监听19端口(包括TCP和UDP),其中UDP协议存在“Chargen UDP服务远程拒绝服务攻击漏洞”. chargen一般不会使用,所以直 ...
 
随机推荐
- 13.git别名
			
虽然别名不是很重要,但是你大概应该知道如何使用它们. Git 并不会在你输入部分命令时自动推断出你想要的命令. 如果不想每次都输入完整的 Git 命令,可以通过 git config 文件来轻松地为每 ...
 - SQL-SERVER学习(二) 数据表的存储过程
			
在C语言的程序设计中,会把一个重复使用的功能提取出来,做成一个的函数,这样就可以减少冗余代码,且更方便维护.调用.在面向对象的设计语言中,会把一个重复使用的功能提取出来,做成一个类,同样也是为了减少冗 ...
 - C/C++文件读取
			
https://blog.csdn.net/stpeace/article/details/12404925
 - SpringBoot页面访问处理
			
SpringBoot页面访问处理 1.介绍 Springboot推荐使用thymeleaf模板引擎搭载html页面实现jsp动态渲染效果,因此这里才会用该种方案进行. 2.集成步骤 引入thymele ...
 - js数组                                                                                                         标签:               javascript                                            2016-08-03 14:15             131人阅读              评论(0)              收藏
			
数组排序 reverse()方法 reverse()方法会反转数组的顺序. sort()方法 默认情况下sort()方法按升序排列数组项.为实现排序sort()方法调用每项的toString(),然后 ...
 - webpack之react开发前准备
			
今天抽出空来,翻了翻webpack之react的书籍,看到刚出的es6语法,貌似是简单了不少,但是兼容性确实不容乐观,如果实在要用那也不是不可以的,首先就跟随我来看下这个插件吧: Babel:这个插件 ...
 - 使用matlab对图像进行傅里叶变换
			
原图: (0) 代码: I=imread('1.jpg'); I=rgb2gray(I); I=im2double(I); F=fft2(I); F=fftshift(F); F=abs(F); T= ...
 - linux 安装pip 和python3
			
前言: python3应该是python的趋势所在,当然目前争议也比较大,这篇随笔的主要目的是记录在linux6.4下搭建python3环境的过程 以及碰到的问题和解决过程. 另外,如果本机安装了py ...
 - JAVA二叉树递归构造、二叉树普通遍历及递归遍历
			
二叉树类: package com.antis.tree; public class BinaryTree { int data; //根节点数据 BinaryTree left; //左子树 Bin ...
 - Pollard_rho 因数分解
			
Int64以内Rabin-Miller强伪素数测试和Pollard 因数分解的算法实现 选取随机数\(a\) 随机数\(b\),检查\(gcd(a - b, n)\)是否大于1,若大于1则\(a - ...