我的网页附加码实现
在网页编程中,经常需要使用到附加码这样的一个东西,防止黑客用程序用穷举法去破解密码。下面是我的一个附加码的Servlet实现。
1
import java.awt.
*
;
2
import java.awt.image.
*
;
3
import java.io.
*
;
4
import java.util.Random;
5
import javax.servlet.
*
;
6
import javax.servlet.http.
*
;
7![]()
8
import com.sun.image.codec.jpeg.
*
;
9![]()
10![]()
public
class
KeyImage extends HttpServlet
{
11![]()
12
private static final String CONTENT_TYPE = "text/html; charset=GBK";
13![]()
14
//Initialize global variables
15![]()
public void init() throws ServletException
{
16![]()
17
}
18![]()
19![]()
/**//**
20
* 随机数生成器
21
*/
22
private static Random random = new Random();
23![]()
24![]()
/**//**
25
* 系统所有的字符
26
*/
27
private static Font[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
28![]()
29![]()
/**//**
30
* 排除的一些字体(这些字体会显示不正常)
31
*/
32
private static java.util.Set excludeFonts = new java.util.HashSet();
33![]()
34![]()
static
{
35
excludeFonts.add("Cursor");
36
excludeFonts.add("Marlett");
37
excludeFonts.add("Symbol");
38
excludeFonts.add("Webdings");
39
excludeFonts.add("Wingdings");
40
excludeFonts.add("Wingdings 2");
41
}
42![]()
43![]()
/**//**
44
* 图片的宽度
45
*/
46
private static int imageWidth = 90;
47![]()
48![]()
/**//**
49
* 图片的高度
50
*/
51
private static int imageHeight = 30;
52![]()
53![]()
/**//**
54
* 背景颜色
55
*/
56
private static Color backgroundColor = Color.WHITE;
57![]()
58![]()
/**//**
59
* 输出的字符数
60
*/
61
private static int characterNumber = 4;
62![]()
63![]()
/**//**
64
* 最终附加码的字符串
65
*/
66
private StringBuffer keyBuf = null;
67![]()
68![]()
/**//**
69
* 字符的颜色数组
70
*/
71![]()
private static Color[] colors = new Color[]
{Color.BLACK, Color.BLUE,
72
Color.CYAN, Color.DARK_GRAY, Color.GRAY, Color.GREEN, Color.MAGENTA,
73
Color.RED};
74![]()
75![]()
/**//**
76
* 获得随机的X值(范围在5到9之间变化)
77
* @return int
78
*/
79![]()
private int randomX()
{
80
return random.nextInt(5) + 5;
81
}
82![]()
83![]()
/**//**
84
* 获得随机的Y值(范围在20到24之间变化)
85
* @return int
86
*/
87![]()
private int randomY()
{
88
return random.nextInt(5) + 20;
89
}
90![]()
91![]()
/**//**
92
* 随机产生字符的大小
93
* @return int 随机字符大小
94
*/
95![]()
private int randomSize()
{
96
return random.nextInt(5) + 20;
97
}
98![]()
99![]()
/**//**
100
* 随机产生Font实例
101
* @return Font 随机Font实例
102
*/
103![]()
private Font randomFont()
{
104
Font font = null;
105![]()
106![]()
if (fonts != null)
{
107
font = fonts[random.nextInt(fonts.length)];
108
font = font.deriveFont(random.nextInt(3), randomSize());
109![]()
} else
{
110
font = new Font("Arial Black", Font.PLAIN, 15);
111
}
112![]()
113![]()
while (excludeFonts.contains(font.getName()))
{
114![]()
if (fonts != null)
{
115
font = fonts[random.nextInt(fonts.length)];
116
font = font.deriveFont(random.nextInt(3), randomSize());
117![]()
} else
{
118
font = new Font("Arial Black", Font.PLAIN, 15);
119
}
120
}
121![]()
122
log("Current Font: " + font.getName() + " Family: " + font.getFamily() + " Font Name: " + font.getFontName());
123![]()
124
return font;
125
}
126![]()
127![]()
/**//**
128
* 随机生成一个Color实例(除了背景)
129
* @return Color 随机Color实例
130
*/
131![]()
private Color randomColor()
{
132
int index = random.nextInt(colors.length);
133
log("Color index is: " + index);
134![]()
135
return colors[index];
136
}
137![]()
138![]()
/**//**
139
* 写入一个字符
140
* @param g Graphics
141
* @param x int
142
* @param y int
143
*/
144![]()
private void drawCharacter(Graphics g, int x, int y)
{
145
int ri = (int) (Math.random() * 10); // 随机生成的数字
146
keyBuf.append(ri);
147
g.setColor(randomColor());
148
g.setFont(randomFont());
149
g.drawString(String.valueOf(ri), x, y);
150
}
151![]()
152![]()
/**//**
153
* 绘制背景
154
* @param g Graphics
155
* @param color Color
156
* @param x int
157
* @param y int
158
* @param width int
159
* @param height int
160
*/
161
private void drawBackground(Graphics g, Color color, int x, int y, int width,
162![]()
int height)
{
163
g.setColor(color);
164
g.fillRect(x, y, width, height);
165
}
166![]()
167![]()
/**//**
168
* 绘制干扰点,干扰线
169
* @param g Graphics
170
* @param width int
171
* @param height int
172
*/
173![]()
private void drawInterrupt(Graphics g, int width, int height)
{
174
int numbers = random.nextInt(100) + 50; // 50到149个干扰点
175
g.setColor(Color.BLACK);
176![]()
177![]()
for (int i = 0; i < numbers; i++)
{
178
g.fillRect(random.nextInt(width), random.nextInt(height), 1, 1);
179
}
180![]()
181
g.drawLine(0, random.nextInt(height), width, random.nextInt(height));
182
}
183![]()
184![]()
/**//**
185
* Process the HTTP Get request
186
* 随机生成数字的策略:
187
* 1.随机渐变色(包括文字和背景,暂时不实现)
188
* 2.所有可打印字符(这里暂时用数字)
189
* 3.字符大小随机变化
190
* 4.位置不固定
191
* 5.象素行或列随机错位
192
* @param request HttpServletRequest
193
* @param response HttpServletResponse
194
* @throws ServletException
195
* @throws IOException
196
*/
197
public void doGet(HttpServletRequest request, HttpServletResponse response)
198![]()
throws ServletException, IOException
{
199![]()
200
BufferedImage image = new BufferedImage(imageWidth, imageHeight,
201
BufferedImage.TYPE_INT_RGB);
202
Graphics g = image.getGraphics();
203![]()
204
drawBackground(g, backgroundColor, 0, 0, imageWidth, imageHeight);
205![]()
206
keyBuf = new StringBuffer();
207
int offset = 0; // 偏移量
208![]()
for (int i = 0; i < characterNumber; i++)
{
209
drawCharacter(g, randomX() + offset, randomY());
210
offset += imageWidth / characterNumber;
211
}
212![]()
213
drawInterrupt(g, imageWidth, imageHeight);
214![]()
215
response.setHeader("Cache-Control", "no-store");
216
response.setDateHeader("Expires", 0);
217
response.setContentType("image/jpeg");
218![]()
219
ServletOutputStream out = response.getOutputStream();
220![]()
221
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
222
encoder.encode(image);
223
out.close();
224![]()
225
// 保存附加码
226
request.getSession().setAttribute("_key", keyBuf.toString());
227
log("The addtional code is: " + keyBuf.toString());
228
}
229![]()
230
//Clean up resources
231![]()
public void destroy()
{
232
}
233![]()
234![]()
/**//**
235
* 改写服务器日志的输出
236
* @param msg String 要输出的信息
237
*/
238![]()
public void log(String msg)
{
239
super.log(msg);
240
}
241![]()
242![]()
/**//**
243
* 改写服务器日志的输出
244
* @param message String 要输出的信息
245
* @param t Throwable 抛出的意外
246
*/
247![]()
public void log(String message, Throwable t)
{
248
t.printStackTrace(System.out);
249
super.log(message, t);
250
}
251
}
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
附加码的效果图: