网页HTML中电子邮箱(Email)地址的加密和混淆防采集

邮箱里垃圾邮件一直有很多,这让我不得不重新审视,发布在网页上的电子邮箱地址,为了避免垃圾邮件,我刻意将@更换成#,也许这在十年前是个不错的办法,但是随着神经网络和机器学习新算法的发展,这一类小手段也面临失效的风险,因为大部分都是通过修改电子邮箱地址的“@”符号,通过正则表达式筛选和特征值匹配,比如hotmail.com、gmail.com、163.com这一类疑似电子邮箱地址的特征,还是可以抓取到电子邮箱地址,所以在将Email发布到HTML网页之前我们要对其进行加密和混淆。

下面我以john@example.com为例,介绍几种加密和混淆的反垃圾邮件手段。

1. 生成图片

利用传统的图灵测试CAPTCHA,将防止采集的电子邮箱地址生成图片,利用机器不能识别的特性,来区别人和机器,生成图片的方式有很多,除了高大上的Photoshop外,甚至可以使用系统自带的绘图工具来完成,另外希望偷懒的话,还有一些在线工具可以帮助到你,比如《Top 10 Websites to Turn Your Email Address into An Image》

继续阅读

ASP/VBScript巧用CAPICOM实现随机数、Hash(MD5/SHA1)和Base64编解码

其实很早就想介绍这个Windows内置的ActiveX/COM组件,我前面有一篇文章介绍如何借用.NET Framework实现类似于SHA1和MD5哈希算法,如果大家对此感兴趣也可以看一下。

好,言归正传,今天我要介绍的是如何让VBScript利用Windows原生自带的CAPICOM组件来实现随机数、Hash(MD5/SHA1)以及Base64算法,当然在VBScript的世界里,这些算法都有免组件的纯代码实现,当然使用组件的好处就是代码简洁和运行效率的提高,所以我们不妨尝试一下。
既然今天介绍的主角是CAPICOM,当然我们要推荐参考微软的MSDN文档,大家不妨先大致浏览一番,可能大家很快发现下面这段提示:

CAPICOM is a 32-bit only component that is available for use in the following operating systems: Windows Server 2008, Windows Vista and Windows XP. Instead, use the .NET Framework to implement security features.

继续阅读

浅议Web在线交易系统涉及的安全场景

之前一次课程的作业,我想存着还不如贴出来供大家拍砖。当然很多是一些个人想法,可能叙述得比较乱,不当之处还望批评指正。

现有的简单的在线交易场景如下图所示:

简单在线交易流程示意图

其中涉及到的数据安全和个人隐私主要有:客户账户和密码,信用卡及相关个人信息。

继续阅读

ASP/VBScript 利用.NET Framework实现PHP sha1() md5()

其实.NET Framework的一些库,ASP是可以直接借来用的,这点我在《ASP/VBScript访问并使用.NET Framework对象》文中已经做了简单的说明,今天正好又遇到一个借用.NET Framework实现某个特殊功能的例子。

在PHP中要计算文本的SHA-1其实很容易,直接使用sha1()这个函数就能轻松搞定了,但是在ASP中就杯具了,没有现成的函数,只能靠手写代码,包括md5()这些常用的哈希函数都要自己编码,好在已经有大牛帮我们写好代码了,我们只需要直接捡现成的用就可以了,比如说MD5就已经有不错的ASP/VBScript版本,关于不同语言的MD5实现可以参考在这里。好了,下面谈下比较棘手的SHA-1算法吧,你肯定说这个也有现成的ASP代码,是的,而且国内著名的ASP博客程序PJ-Blog已经内置了这种SHA-1算法了,那有什么好纠结的呢?PJ的SHA-1代码源于这里,这个实现代码其实是JavaScript版本的,因为IIS的ASP技术默认支持VBScript和JavaScript/JScript两种脚本语言,所以我们可以直接拿来和VBScript混合使用。似乎这样也没有什么问题,但是对于ASP这种古老的技术而言,性能一直是其最大的瓶颈,而ASP性能建议上提到,不要混用两种脚本语言,也就是说混用VBScript和JScript会导致服务器缓存两个脚本解释引擎,而且会导致上下文切换的开销,所以性能上就有所损耗了,由于初始配置的IIS是把VBScript作为默认脚本语言,再加上JScript的对象模型,所以和JScript比起来VBScript可能性能上要好一点。

好吧,下面我们要做的是搞个VBScript版本的SHA-1,在这里我偷懒了点,求助了万能的谷歌,然后找到了一篇文章《Replicating PHP’s sha1() in VBScript》,其中就提到了,借用.NET Framework的技术实现了VBScript版本的sha1,由于是通过Server.CreateObject实现的,所以代码比较简洁,性能上也应该说得过去,在这里我改写成类似PHP的sha1()函数:

继续阅读

JavaScript类似于eval加密编码方式的解密解码过程(Unpack)

类似于下面这样的代码,肯定你在研究前端JavaScript脚本时遇到过:

1
2
3
4
5
6
7
8
9
10
eval(function(p,a,c,k,e,r){
e=String;if(!''.replace(/^/,String))
{while(c--)r[c]=k[c]||c;
k=[function(e){return r[e]}];
e=function(){return'\\w+'};
c=1};while(c--)if(k[c])
p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),
k[c]);return p}
('0("1 2");',3,3,
'alert|Hello|World'.split('|'),0,{}))

很多朋友以为这段代码是“加密”的,其实这也谈不上是加密,只能算是一种编码(Encode)或者也可以成为是一种打包(packer),类似于base64这样的编码,都是可以以一定方式还原的,当然也就是“解密”了。

我们仔细分析这一段代码,不难发现代码开头都是eval,特征字符串是function(p,a,c,k,e,r)或者是function(p,a,c,k,e,d),其实这样的pack方式是dean edwards提出的,你可以访问其个人主页以获取这方面的最新信息。后来还有一些编码打包方式也是eval开头,但是特征字符串p,a,c,k,e,r(d)改变了,我们姑且称为是这种打包方式的一个变种吧,其实解码很简单,我们回顾一下JavaScript脚本中eval含义及用法。

继续阅读

Base24、Base64编码的几种程序实现

可能很多人听说过Base64编码,很少有人听说过Base24编码,Base24编码主要应用在序列号生成上,其实基本的算法思想都是一样的,只是编码的模式有点变化。
Base64所对应的编码表是
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
共计64位。
而Base24所对应的编码表是
BCDFGHJKMPQRTVWXY2346789
共计24位,这里主要去掉了一些对于序列号来说不容易识别和容易混淆的字符。

具体算法网上都有介绍我就不再赘述,下面直接谈怎么编码实现吧:-)

对于Base64算法的C语言实现,大家可以参考Bob Trower的经典开源项目b64.c,网址是http://base64.sourceforge.net/

在这里我要谈的是如何用ASP进行Base64编码,网上搜索出的一大堆算法不是太复杂就是运行不准确,其实ASP的Base64编码可以很简单,当然要用到服务器的一个COM组件XmlDom,具体思路是这样的,首先创建个临时的节点tmp,然后给结点tmp,设置datatype = “bin.base64″,这样就可以进行相应的编解码了,对于文本字符串的编解码还要用ADODB.Stream进行一次编码转换。

Base64的ASP实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
Class CBase64
  Private objXmlDom
  Private objXmlNode
 
  ' GetObjectParam() 这个函数实现参考了开源项目PJBlog
  Private Function GetObjectParam()
   On Error Resume Next
   Dim Temp
   GetObjectParam = "Microsoft.XMLDOM"
   Err = 0
   Dim TmpObj
   Set TmpObj = Server.CreateObject(GetObjectParam)
   Temp = Err.Number
   If Temp = 1 Or Temp = -2147221005 Then
       GetObjectParam = "Msxml2.DOMDocument.5.0"
    End If
    Err.Clear
    Set TmpObj = Nothing
   Err = 0
  End Function
 
  Private Sub Class_Initialize()
      Set objXmlDom = Server.CreateObject(GetObjectParam())
  End Sub
 
  Private Sub Class_Terminate()
      Set objXmlDom = Nothing
  End Sub
 
  Public Function encode(AnsiCode)
    encode = ""
    Set objXmlNode = objXmlDom.createElement("tmp")
    objXmlNode.datatype = "bin.base64"
    objXmlNode.nodeTypedvalue = AnsiCode
    encode = objXmlNode.Text
    Set objXmlNode = Nothing
  End Function
 
  Public Function decode(base64Code)
    On Error Resume Next
    decode = ""
    Set objXmlNode = objXmlDom.createElement("tmp")
    objXmlNode.datatype = "bin.base64"
    objXmlNode.Text = base64Code
    decode = objXmlNode.nodeTypedvalue
    Set objXmlNode = Nothing
    If Err Then
        Err.Clear
    End If
  End Function
 
  ' 以下函数编码字符串
  Public Function encodeText(ByVal str)
    On Error Resume Next
    Dim ado, r: r = ""
    If str <> "" Then
    Set ado = Server.CreateObject("ADODB.Stream")
        With ado
            .Charset = "gb2312"
            .Type = 2
            If .State = 0 Then .Open
            .WriteText str
            .Position = 0
            .Type = 1
            r = encode(.Read(-1))
            .Close
        End With
    Set ado = Nothing
    End If
    If Err Then Err.Clear: r = ""
    encodeText = r
  End Function
 
  ' 以下函数解码字符串
  Public Function decodeText(ByVal str)
    On Error Resume Next
    Dim ado, r: r = ""
    If str <> "" Then
    Set ado = Server.CreateObject("ADODB.Stream")
        With ado
            .Charset = "gb2312"
            .Type = 1
            If .State = 0 Then .Open
            .Write (decode(str))
            .Position = 0
            .Type = 2
            r = .ReadText(-1)
            .Close
        End With
    Set ado = Nothing
    End If
    If Err Then Err.Clear: r = ""
    decodeText = r
  End Function
End Class

写到这里想起以前项目里改写过一段Base64和16进制互转的代码,在这里与大家分享下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
' Base64转16进制
Function B64ToHex(ByVal strContent)
  Dim i,strReturned, b64pad, _
       b64map, chTemp, intLocate, k , slop
  strReturned = "" : k = 0
  b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZ" &_
              "abcdefghijklmnopqrstuvwxyz0123456789+/"
  b64pad="="
  For i=0 To Len(strContent)-1
     chTemp = Mid(strContent, i+1, 1)
     If chTemp = b64pad Then Exit For
     intLocate = InStr(1, b64map, chTemp, 0)-1
     If intLocate > -1 Then
         Select Case K
           Case 0
           strReturned = strReturned &_
                             Int2Char(Int(intLocate / 4))
           slop = intLocate And 3 :  k = 1
           Case 1
           strReturned = strReturned &_
                              Int2Char( (slop * 4) Or (Int(intLocate / 16)) )
          slop = intLocate And &h0f :  k = 2
          Case 2
          strReturned = strReturned &_
                             Int2Char(slop) & Int2Char(Int(intLocate / 4))
          slop = intLocate And 3  : k=3
          Case Else
          strReturned = strReturned &_
                             Int2Char( (slop * 4) Or (Int(intLocate / 16)) ) &_
                             Int2Char(intLocate And &h0f)
          k = 0
        End Select
     End If
  Next
  If k=1 Then strReturned = strReturned & Int2Char(slop * 4)
  B64ToHex = strReturned
End Function
 
' 16进制转Base64
Function HexToB64(ByVal strContent)
  Dim i, c, strReturned, b64map, b64pad, intLen
  b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZ" &_
             "abcdefghijklmnopqrstuvwxyz0123456789+/"
  b64pad="="
  intLen = Len(strContent)
  For i=0 To intLen-3 Step 3
      c=Clng("&h" & Mid(strContent,i+1,3))
      strReturned = strReturned &_
                         Mid(b64map, Int(c / 64 +1), 1) &_
                         Mid(b64map, (c And 63)+1, 1)
  Next
 
  If i+1=intLen Then
     c =Clng("&h" & Mid(strContent,i+1,1))
     strReturned = strReturned & Mid(b64map, c * 4 + 1, 1)
  ElseIf i+2=intLen Then
     c =Clng("&h" & Mid(strContent,i+1,2))
     strReturned = strReturned & Mid(b64map, Int(c / 4) + 1, 1) &_
                        Mid(b64map, (c And 3)*16+1, 1)		
  End If
 
  While (Len(strReturned) And 3) >0
      strReturned = strReturned & b64pad
  Wend
  HexToB64 = strReturned
End Function

有关Base24的代码实现网上也有很多,这里给出两种不同程序语言的实现供参考。

Base24的C语言实现

static const char sel[] = {
	'B','C','D','F','G',
	'H','J','K','M','P',
	'Q','R','T','V','W',
	'X','Y','2','3','4',
	'6','7','8','9', '\0'};
 
char *b24e(char *buf, unsigned char *byst, size_t sizeOfBytes)
{
	int i = 0;
	unsigned char *p = byst;
	while ((size_t)(i = (p-byst)) < sizeOfBytes) {
		buf[2*i] = sel[((*p) >> 4)];
		buf[(2*i)+1] = sel[23 - ((*p) & 0x0f)];
		p++;
	}
	buf[(2*i)+1] = '\0';
	return buf;
}
 
unsigned char *b24d(unsigned char *buf, char *str, size_t countOfChars)
{
	size_t i;
	char *p = str;
	char *loc[2];
	unsigned char n[2];
	if (countOfChars % 2)
		return NULL;
	for (i = 0; i < (countOfChars>>1); i++) {
 
		loc[0] = strchr( sel, str[2*i] );
		loc[1] = strchr( sel, str[ ( 2*i ) + 1 ] );
		if (loc[0] == NULL || loc[1] == NULL)
			return NULL;
		n[0] = (unsigned char)( loc[0] - sel );
		n[1] = 23 - (unsigned char)( loc[1] - sel );
		buf[i] = (unsigned char)((n[0] << 4) | n[1]);
	}
	return buf;
}

后来由于项目需要,我特地改写了C#版。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public static class Base24
{
  private static string sel = "BCDFGHJKMPQRTVWXY2346789";
 
  public static string Encode(string Text)
  {
    int i = 0;
    int Pos = 0;
    char []Buf = new char[Text.Length<<1];
 
    while ((i = Pos) < Text.Length)
    {
        Buf[i<<1] = sel[(Text[Pos]) >> 4];
        Buf[(i<<1) + 1] = sel[23 - (Text[Pos] & 0x0F)];
        Pos++;
     }
 
        return new string(Buf);
    }
 
    public static string Decode(string Text)
    {
        if (Text.Length % 2 != 0)
            return null;
 
        int [] NPos = new int[2];
        char[] N = new char[2];
        char[] Buf = new char[Text.Length >> 1];
 
        for (int i = 0; i < (Text.Length >> 1); i++)
        {
            NPos[0] = sel.IndexOf(Text[ i<<1 ]);
            NPos[1] = 23 - sel.IndexOf(Text[(i<<1) + 1]);
            if (NPos[0] < 0 || NPos[1] < 0) {
                return null;
            }
 
            Buf[i] = ((char)((NPos[0] << 4) | NPos[1]));
        }
            return new string(Buf);
    }
}
  1. Base64 : Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一。[更多]