开发者社区> 5na6pyt44b2ti> 正文

iOS逆向 07:Hash算法

简介: iOS逆向 07:Hash算法
+关注继续查看

本文主要介绍Hash算法


Hash介绍


Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数


简单来说,hash算法(即散列函数),是一种单向密码体制,即它是一个从明文到密文的不可逆的映射,只有加密过程,没有解密过程。同时,哈希函数可以将任意长度的输入经过变化以后得到固定长度的输出。哈希函数的这种单向特征和输出数据长度固定的特征使得它可以生成消息或者数据。


Hash的特点


  • 算法是公开的
  • 相同数据运算,得到的结果是一样的(同样的数据,得到的结果是一样的)
  • 不同数据运算,得到的结果是定长的,如MD5得到的结果默认是128位,32个字符(16进制标识)。
  • 无法逆运算
  • 是信息摘要、信息“指纹”,是用来做数据识别的、完整性检查的。


Hash用途


  • 1、用户密码的加密
  • 2、搜索引擎
  • 3、版权
  • 4、数字签名
  • ......


数据传输/存储原则网络传输数据 + 本地保存数据 + 服务端保存数据等 ,这些是隐私数据,绝对不能明文,一定是密文传输/存储。


常见的Hash算法


常见的hash算法主要有MD5、SHA-1、SHA-256、SHA-512等


MD5


MD4(RFC 1320)是 MIT 的Ronald L. Rivest在 1990 年设计的,MD 是 Message Digest(消息摘要) 的缩写。它适用在32位字长的处理器上用高速软件实现——它是基于 32位操作数的位操作来实现的。


MD5(RFC 1321)是 Rivest 于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联,与 MD4 相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好。


Message Digest Algorithm MD5(消息摘要算法5)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。是计算机广泛使用的杂凑算法之一,将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。


特点


  • 1、压缩性:任意长度的数据,算出的MD5值长度都是固定的。
  • 2、容易计算:从原数据计算出MD5值很容易。
  • 3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
  • 4、强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。


应用场景


  • 一致性验证
  • 数字签名
  • 安全访问认证


SHA-1、SHA-256、SHA-512


安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。


SHA1是由NIST NSA设计为同DSA一起使用的,它对长度小于264的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1 设计时基于和MD4相同原理,并且模仿了该算法。


SHA-2 SHA-224、SHA-256、SHA-384,和SHA-512并称为SHA-2。 新的哈希函数并没有接受像SHA-1一样的公众密码社区做详细的检验,所以它们的密码安全性还不被大家广泛的信任。 虽然至今尚未出现对SHA-2有效的攻击,它的算法跟SHA-1基本上仍然相似;因此有些人开始发展其他替代的哈希算法。


注:这里只做简单介绍,并不展开详细说明,有兴趣的可以参考以下链接


密码加密


这里我们分别来对比以下四种,对密码的加密方式


  • 1、直接使用MD5(信息摘要算法)
  • 2、MD5加盐
  • 3、HMAC加密方案
  • 4、添点东西


准备工作


在进行演示前,首先封装常用的Hash算法

<!--h文件-->
#import <Foundation/Foundation.h>

@interface NSString (Hash)
    
#pragma mark - 散列函数
    /**
     *  计算MD5散列结果
     *
     *  终端测试命令:
     *  @code
     *  md5 -s "string"
     *  @endcode
     *
     *  <p>提示:随着 MD5 碰撞生成器的出现,MD5 算法不应被用于任何软件完整性检查或代码签名的用途。<p>
     *
     *  @return 32个字符的MD5散列字符串
     */
- (NSString *)md5String;
    
    /**
     *  计算SHA1散列结果
     *
     *  终端测试命令:
     *  @code
     *  echo -n "string" | openssl sha1
     *  @endcode
     *
     *  @return 40个字符的SHA1散列字符串
     */
- (NSString *)sha1String;
    
    /**
     *  计算SHA256散列结果
     *
     *  终端测试命令:
     *  @code
     *  echo -n "string" | openssl sha -sha256
     *  @endcode
     *
     *  @return 64个字符的SHA256散列字符串
     */
- (NSString *)sha256String;
    
    /**
     *  计算SHA 512散列结果
     *
     *  终端测试命令:
     *  @code
     *  echo -n "string" | openssl sha -sha512
     *  @endcode
     *
     *  @return 128个字符的SHA 512散列字符串
     */
- (NSString *)sha512String;
    
#pragma mark - HMAC 散列函数
    /**
     *  计算HMAC MD5散列结果
     *
     *  终端测试命令:
     *  @code
     *  echo -n "string" | openssl dgst -md5 -hmac "key"
     *  @endcode
     *
     *  @return 32个字符的HMAC MD5散列字符串
     */
- (NSString *)hmacMD5StringWithKey:(NSString *)key;
    
    /**
     *  计算HMAC SHA1散列结果
     *
     *  终端测试命令:
     *  @code
     *  echo -n "string" | openssl sha -sha1 -hmac "key"
     *  @endcode
     *
     *  @return 40个字符的HMAC SHA1散列字符串
     */
- (NSString *)hmacSHA1StringWithKey:(NSString *)key;
    
    /**
     *  计算HMAC SHA256散列结果
     *
     *  终端测试命令:
     *  @code
     *  echo -n "string" | openssl sha -sha256 -hmac "key"
     *  @endcode
     *
     *  @return 64个字符的HMAC SHA256散列字符串
     */
- (NSString *)hmacSHA256StringWithKey:(NSString *)key;
    
    /**
     *  计算HMAC SHA512散列结果
     *
     *  终端测试命令:
     *  @code
     *  echo -n "string" | openssl sha -sha512 -hmac "key"
     *  @endcode
     *
     *  @return 128个字符的HMAC SHA512散列字符串
     */
- (NSString *)hmacSHA512StringWithKey:(NSString *)key;
    
#pragma mark - 文件散列函数
    
    /**
     *  计算文件的MD5散列结果
     *
     *  终端测试命令:
     *  @code
     *  md5 file.dat
     *  @endcode
     *
     *  @return 32个字符的MD5散列字符串
     */
- (NSString *)fileMD5Hash;
    
    /**
     *  计算文件的SHA1散列结果
     *
     *  终端测试命令:
     *  @code
     *  openssl sha -sha1 file.dat
     *  @endcode
     *
     *  @return 40个字符的SHA1散列字符串
     */
- (NSString *)fileSHA1Hash;
    
    /**
     *  计算文件的SHA256散列结果
     *
     *  终端测试命令:
     *  @code
     *  openssl sha -sha256 file.dat
     *  @endcode
     *
     *  @return 64个字符的SHA256散列字符串
     */
- (NSString *)fileSHA256Hash;
    
    /**
     *  计算文件的SHA512散列结果
     *
     *  终端测试命令:
     *  @code
     *  openssl sha -sha512 file.dat
     *  @endcode
     *
     *  @return 128个字符的SHA512散列字符串
     */
- (NSString *)fileSHA512Hash;
@end

<!--m文件-->
#import "NSString+Hash.h"
#import <CommonCrypto/CommonCrypto.h>

@implementation NSString (Hash)
    
#pragma mark - 散列函数
- (NSString *)md5String {
    const char *str = self.UTF8String;
    uint8_t buffer[CC_MD5_DIGEST_LENGTH];
    
    CC_MD5(str, (CC_LONG)strlen(str), buffer);
    
    return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
    
- (NSString *)sha1String {
    const char *str = self.UTF8String;
    uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
    
    CC_SHA1(str, (CC_LONG)strlen(str), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
    
- (NSString *)sha256String {
    const char *str = self.UTF8String;
    uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
    
    CC_SHA256(str, (CC_LONG)strlen(str), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
    
- (NSString *)sha512String {
    const char *str = self.UTF8String;
    uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
    
    CC_SHA512(str, (CC_LONG)strlen(str), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
    
#pragma mark - HMAC 散列函数
- (NSString *)hmacMD5StringWithKey:(NSString *)key {
    const char *keyData = key.UTF8String;
    const char *strData = self.UTF8String;
    uint8_t buffer[CC_MD5_DIGEST_LENGTH];
    
    CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer);
    
    return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
    
- (NSString *)hmacSHA1StringWithKey:(NSString *)key {
    const char *keyData = key.UTF8String;
    const char *strData = self.UTF8String;
    uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
    
    CCHmac(kCCHmacAlgSHA1, keyData, strlen(keyData), strData, strlen(strData), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
    
- (NSString *)hmacSHA256StringWithKey:(NSString *)key {
    const char *keyData = key.UTF8String;
    const char *strData = self.UTF8String;
    uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
    
    CCHmac(kCCHmacAlgSHA256, keyData, strlen(keyData), strData, strlen(strData), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
    
- (NSString *)hmacSHA512StringWithKey:(NSString *)key {
    const char *keyData = key.UTF8String;
    const char *strData = self.UTF8String;
    uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
    
    CCHmac(kCCHmacAlgSHA512, keyData, strlen(keyData), strData, strlen(strData), buffer);
    
    return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
    
#pragma mark - 文件散列函数
    
#define FileHashDefaultChunkSizeForReadingData 4096
    
- (NSString *)fileMD5Hash {
    NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
    if (fp == nil) {
        return nil;
    }
    
    CC_MD5_CTX hashCtx;
    CC_MD5_Init(&hashCtx);
    
    while (YES) {
        @autoreleasepool {
            NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
            
            CC_MD5_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
            
            if (data.length == 0) {
                break;
            }
        }
    }
    [fp closeFile];
    
    uint8_t buffer[CC_MD5_DIGEST_LENGTH];
    CC_MD5_Final(buffer, &hashCtx);
    
    return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
    
- (NSString *)fileSHA1Hash {
    NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
    if (fp == nil) {
        return nil;
    }
    
    CC_SHA1_CTX hashCtx;
    CC_SHA1_Init(&hashCtx);
    
    while (YES) {
        @autoreleasepool {
            NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
            
            CC_SHA1_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
            
            if (data.length == 0) {
                break;
            }
        }
    }
    [fp closeFile];
    
    uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1_Final(buffer, &hashCtx);
    
    return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
    
- (NSString *)fileSHA256Hash {
    NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
    if (fp == nil) {
        return nil;
    }
    
    CC_SHA256_CTX hashCtx;
    CC_SHA256_Init(&hashCtx);
    
    while (YES) {
        @autoreleasepool {
            NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
            
            CC_SHA256_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
            
            if (data.length == 0) {
                break;
            }
        }
    }
    [fp closeFile];
    
    uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
    CC_SHA256_Final(buffer, &hashCtx);
    
    return [self stringFromBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
}
    
- (NSString *)fileSHA512Hash {
    NSFileHandle *fp = [NSFileHandle fileHandleForReadingAtPath:self];
    if (fp == nil) {
        return nil;
    }
    
    CC_SHA512_CTX hashCtx;
    CC_SHA512_Init(&hashCtx);
    
    while (YES) {
        @autoreleasepool {
            NSData *data = [fp readDataOfLength:FileHashDefaultChunkSizeForReadingData];
            
            CC_SHA512_Update(&hashCtx, data.bytes, (CC_LONG)data.length);
            
            if (data.length == 0) {
                break;
            }
        }
    }
    [fp closeFile];
    
    uint8_t buffer[CC_SHA512_DIGEST_LENGTH];
    CC_SHA512_Final(buffer, &hashCtx);
    
    return [self stringFromBytes:buffer length:CC_SHA512_DIGEST_LENGTH];
}
    
#pragma mark - 助手方法
    /**
     *  返回二进制 Bytes 流的字符串表示形式
     *
     *  @param bytes  二进制 Bytes 数组
     *  @param length 数组长度
     *
     *  @return 字符串表示形式
     */
- (NSString *)stringFromBytes:(uint8_t *)bytes length:(int)length {
    NSMutableString *strM = [NSMutableString string];
    
    for (int i = 0; i < length; i++) {
        [strM appendFormat:@"%02x", bytes[i]];
    }
    
    return [strM copy];
}
@end


方式一:直接使用MD5


终端演示


  • md5 -s "123456"
  • MD5 ("123456") ,结果为 e10adc3949ba59abbe56e057f20f883e


代码演示

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSString *pwd = @"123456";
    //传递数据
    pwd = pwd.md5String;
    NSLog(@"pwd - %@", pwd);
}

<!--运行结果-->
 pwd - e10adc3949ba59abbe56e057f20f883e

结论:直接使用MD5不安全,大部分MD5现在通过网站都可以还原


方式二:MD5加固定盐


在方式一的基础上,加上一个固定的字符串,代码演示如下

//加盐
static NSString *salt = @"LKSJDFLKJ";

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSString *pwd = @"123456";
    //传递数据
    pwd = [pwd stringByAppendingString:salt].md5String;
    NSLog(@"pwd - %@", pwd);
}

<!--运行结果-->
pwd - 2cac01acb03a3cc2b96cee3aae4d2276

结论:加固定盐,现在也不安全,因为如果盐泄漏了,也会有数据泄漏的风险


方式三:HMAC加密


HMAC加密,其原理就是判断是否有key,这个key是由服务器动态提供的,保存在手机侧。简单来说,就相当于现在的授权设备,HMAC主要就是检测你的设备是否有授权。其代码演示如下

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSString *pwd = @"123456";
    //传递数据
    //key是动态的,由服务器提供(即一个账号一个key)
    pwd = [pwd hmacMD5StringWithKey:@"CJL"];
    NSLog(@"pwd - %@", pwd);
}

<!--打印结果-->
pwd - b123975de0f19edef5a546bf212bd918

结论:现在这种加密方式,用户密码确实安全了。但是用于服务器登录验证是一个hash值,而不是密码。所以这个hash值也有被拦截的风险。也是不安全的


方式四:HMAC + 时间戳


基于方式三的基础上,我们载增加一些东西一起加密,这个增加的就是时间戳。对于密码来说,加密方式还是采用HMAC加密。只是验证方式发生了变化。原本只是验证hash值即可。现在是在hash值的基础上加上了一个时间期限。例如hash值的有效时间最多是2分钟,超过这个时间就失效了。类似于现在验证码的验证。


主要流程如下:


  • 1、客户端:对密码使用HMAC加密,得到一个hash值A,hash值带上服务器给的时间戳,求得另一个hash值B
  • 2、将客户端得到的Hash值AHash值B发送到服务器进行验证
  • 3、服务器:将传过来的Hash值A,带上服务器的时间戳,得到一个Hash值C,判断Hash值C是否等于传过来的Hash值B,如果不等于,则表示不通过,在时间范围内,再继续验证上一分钟


举例说明


假设现在用户的密码是:123456,


  • 1、客户端:
    • 使用HMAC加密得到的Hash值A = b123975de0f19edef5a546bf212bd918
    • HMAC哈希值 + 时间戳(假设是2021-4-10 17:15:10) 得到的hash值B = 430a60f4989e104e9e903dbdcb84c69a
  • 2、发送到服务器的Hash值
    • Hash值Ab123975de0f19edef5a546bf212bd918
    • hash值B430a60f4989e104e9e903dbdcb84c69a
  • 3、服务端:
    • HMAC哈希值 + 服务器时间戳(假设是2021-4-10 17:15:11) 得到的hash值C = 0cf1dceda0fd58aefd4c7a7b2b08e193
    • 与客户端传入的hash值C不等,继续求HMAC带上上一个时间(2分钟内)的 hash值D = 430a60f4989e104e9e903dbdcb84c69a.与hash值B相等,所以验证通过


例子中所用的演示代码如下

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSString *pwd = @"123456";
    //传递数据
    pwd = [pwd hmacMD5StringWithKey:@"CJL"];//key是动态的,由服务器提供
    NSLog(@"pwd - %@", pwd);
    pwd = [NSString stringWithFormat:@"%@%@",pwd, [self getOtherTimeStrWithString:@"2021-4-10 17:15:10"]].md5String;
    NSLog(@"pwd - %@", pwd);
}


- (NSString *)getOtherTimeStrWithString:(NSString *)formatTime{
    NSLog(@"formatTime - - - - - -%@",formatTime);
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateStyle:NSDateFormatterMediumStyle];
    [formatter setTimeStyle:NSDateFormatterShortStyle];
    [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"]; //(@"YYYY-MM-dd hh:mm:ss") ----------设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制
    //设置时区选择北京时间
    NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"Asia/Beijing"];
    [formatter setTimeZone:timeZone];
    NSDate* date = [formatter dateFromString:formatTime]; //------------将字符串按formatter转成nsdate
    //时间转时间戳的方法:
    NSInteger timeSp = [[NSNumber numberWithDouble:[date timeIntervalSince1970]] integerValue] * 1000;
    NSLog(@"将某个时间转化成 时间戳timeSp:%ld",(long)timeSp); //时间戳的值
    return [NSString stringWithFormat:@"%ld",(long)timeSp];
}


数字签名


目的:验证二进制数据是不是颁发机构颁发的


早期只是给一个数据,扔给我,我就用,这是不安全的


  • 1、数据报文,即原始数据

image.png

后来的数字签名,为了安全,不仅给数据,还给数据的Hash值,但是还是不安全,因为数据、hash值都有可能同时篡改


  • 1、数据报文,即原始数据
  • 2、原始数据的Hash值

image.png

现在的数字签名,除了给数据,同时还给原始数据Hash值进行RSA加密后得到的hash值,其中原始数据HASH值RSA加密后得到的值称为原始数据的 数字签名


  • 1、数据报文,即原始数据
  • 2、原始数据的Hash值
  • 3、数字签名:原始数据Hash值通过RSA加密后得到的结果

image.png


总结


  • HASH算法(散列函数)
    • 不可逆运算(因为无限的数据,存在有限的表示形式,所以会出现 多个不同的数据,有同样的hash值)
    • 相同的数据结果相同
    • 不同的数据长度相同
    • 一般用于做数据的识别,例如密码、版权、百度云数据识别
  • 密码加密
    • md5直接加密,可被查询,容易破解
    • 加固定盐(固定的盐有安全隐患)
    • HMAC:比较好的方案,因为破解的成本 大于 破解后的获益,所以相对安全
    • HASH + 时间戳:这样的方式,每次加密结果不一样,因为受时间的影响比较大
  • 数字签名
    • 算法:RSA + HASH
    • 目的:验证数据的完整性,不被篡改
    • 主要逻辑:
      • 1、原始数据报文进行HASH
      • 2、使用RSA加密 HASH值(这部分数据就是原始数据的签名信息)
      • 3、将原始数据hash值 + 数字签名 一起打包发送传递



版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
如何设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云安全组设置详细图文教程(收藏起来) 阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程。阿里云会要求客户设置安全组,如果不设置,阿里云会指定默认的安全组。那么,这个安全组是什么呢?顾名思义,就是为了服务器安全设置的。安全组其实就是一个虚拟的防火墙,可以让用户从端口、IP的维度来筛选对应服务器的访问者,从而形成一个云上的安全域。
18862 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
28063 0
阿里云服务器安全组设置内网互通的方法
虽然0.0.0.0/0使用非常方便,但是发现很多同学使用它来做内网互通,这是有安全风险的,实例有可能会在经典网络被内网IP访问到。下面介绍一下四种安全的内网互联设置方法。 购买前请先:领取阿里云幸运券,有很多优惠,可到下文中领取。
22080 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
15544 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
20141 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
23538 0
腾讯云服务器 设置ngxin + fastdfs +tomcat 开机自启动
在tomcat中新建一个可以启动的 .sh 脚本文件 /usr/local/tomcat7/bin/ export JAVA_HOME=/usr/local/java/jdk7 export PATH=$JAVA_HOME/bin/:$PATH export CLASSPATH=.
14869 0
166
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载