1.没有实现验证码功能,容易被恶意程序攻击,盗取用户名和密码
2.改进思路------验证码机制,需求:验证码必须能够有效避开恶意程序的识别!
- 随机产生验证码
- 用户识别后填写
- 判断用户识别的正确性
3.关于验证码和恶意程序
- 自动测试原理
- 利用一些特殊的系统函数能够通过代码控制程序,从而模拟用户操作
- 恶意程序
- 使用自动测试原理对目标程序进行控制,从而盗取信息或进行攻击
- 验证码
- 随机产生,用户容易识别,程序难以识别,从而有效避免恶意攻击
4.需要注意的问题
- 验证码必须动态随机产生
- 验证码的显示避开使用标准组件(标签、文件框等)
- 验证码应该附带足够多的障碍增加程序识别难度
5.解决方案
- 随机产生目标验证码
- 将验证码直接绘制于登录对话框
- 验证码中的字符颜色随机改变
- 在验证码区域随机绘制噪点
Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPushButton>
#include "QLoginDialog.h"
class Widget : public QWidget
{
Q_OBJECT
QPushButton m_Login;
QLoginDialog m_logindialog;
private slots:
void on_Login();
public:
explicit Widget(QWidget *parent = nullptr);
~Widget() override;
};
#endif // WIDGET_H
Widget.cpp
#include "Widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent), m_Login(this)
{
m_Login.setText("Test Login Dialog");
connect(&m_Login, SIGNAL(clicked()), this, SLOT(on_Login()));
}
void Widget::on_Login()
{
m_logindialog.show();
}
Widget::~Widget() = default;
QLoginDialog.h
#ifndef QLOGINDIALOG_H
#define QLOGINDIALOG_H
#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QTimer>
class QLoginDialog : public QDialog
{
Q_OBJECT
private:
QLabel UserLabel;
QLabel PwdLabel;
QLabel CaptLabel;
QLineEdit UserEdit;
QLineEdit PwdEdit;
QLineEdit CaptEdit;
QPushButton LoginBtn;
QPushButton CancelBtn;
QString m_user;
QString m_pwd;
QString m_captcha;
Qt::GlobalColor* m_colors;
QTimer m_timer;
private slots:
void LoginBtn_Clicked();
void CancelBtn_Clicked();
void Timer_timeout();
protected:
void paintEvent(QPaintEvent* );
QString getCaptcha(); //获取验证码字符串
Qt::GlobalColor* getColors();
public:
explicit QLoginDialog(QWidget *parent = nullptr);
QString getUser();
QString getPwd();
~QLoginDialog();
};
#endif // QLOGINDIALOG_H
QLoginDialog.cpp
#include "QLoginDialog.h"
#include <QPainter>
#include <QTime>
#include <QDebug>
#include <QMessageBox>
QLoginDialog::QLoginDialog(QWidget *parent) : QDialog(parent, Qt::WindowCloseButtonHint),
UserLabel(this), PwdLabel(this), CaptLabel(this),
UserEdit(this), PwdEdit(this), CaptEdit(this),
LoginBtn(this), CancelBtn(this)
{
UserLabel.setText("User ID:");
UserLabel.move(20, 30);
UserLabel.resize(60, 25);
UserEdit.move(90, 30);
UserEdit.resize(85, 25);
PwdLabel.setText("Password:");
PwdLabel.move(20, 65);
PwdLabel.resize(70, 25);
PwdEdit.move(90, 65);
PwdEdit.resize(180, 25);
PwdEdit.setEchoMode(QLineEdit::Password);
CaptLabel.setText("Captcha:");
CaptLabel.move(20, 100);
CaptLabel.resize(60, 25);
CaptEdit.move(90, 100);
CaptEdit.resize(85, 25);
CancelBtn.setText("Cancel");
CancelBtn.move(85, 145);
CancelBtn.resize(85, 30);
LoginBtn.setText("Login");
LoginBtn.move(180, 145);
LoginBtn.resize(85, 30);
m_timer.setParent(this);
setWindowTitle("Login");
setFixedSize(285, 205);
connect(&m_timer, SIGNAL(timeout()), this, SLOT(Timer_timeout()));
connect(&LoginBtn, SIGNAL(clicked()), this, SLOT(LoginBtn_Clicked()));
connect(&CancelBtn, SIGNAL(clicked()), this, SLOT(CancelBtn_Clicked()));
qsrand(QTime::currentTime().second() * 1000 + QTime::currentTime().msec()); //种下随机种子,把当前时间换算成从这一分钟开始算起的总毫秒数
m_captcha = getCaptcha();
m_colors = getColors();
m_timer.start(100);
}
void QLoginDialog::LoginBtn_Clicked()
{
qDebug() << "LoginBtn_Clicked() Begin";
QString captcha = CaptEdit.text().replace(" ", "");
if( m_captcha.toLower() == captcha.toLower() )
{
m_user = UserEdit.text().trimmed();
m_pwd = PwdEdit.text();
if( m_user == "" )
{
QMessageBox::information(this, "Info", "User ID can NOT be empty!");
}
else if( m_pwd == "" )
{
QMessageBox::information(this, "Info", "Password can NOT be empty!");
}
else
{
done(Accepted);
}
}
else
{
QMessageBox::critical(this, "Error", "The captcha is Not matched!");
m_captcha = getCaptcha();
CaptEdit.selectAll();
}
qDebug() << "LoginBtn_Clicked() End";
}
void QLoginDialog::CancelBtn_Clicked()
{
qDebug() << "CancelBtn_Clicked() Begin";
done(Rejected);
qDebug() << "CancelBtn_Clicked() End";
}
void QLoginDialog::paintEvent(QPaintEvent* )
{
QPainter painter(this);
painter.fillRect(180, 100, 84, 24, Qt::white);
painter.setFont(QFont("Comic Sans MS", 12));
for(int i=0; i<150; i++)
{
painter.setPen(m_colors[i%4]);
painter.drawPoint(180 + qrand() % 84, 100 + qrand() % 24);
}
for(int i=0; i<4; i++)
{
painter.setPen(m_colors[i]);
painter.drawText(180 + 20 * i, 100, 20, 24, Qt::AlignCenter, QString(m_captcha[i]));
}
}
QString QLoginDialog::getCaptcha()
{
QString ret = "";
for(int i=0; i<4; i++)
{
int c = (qrand() % 2) ? 'a' : 'A';
ret += static_cast<QChar>(c + qrand() % 24);
}
return ret;
}
Qt::GlobalColor* QLoginDialog::getColors()
{
static Qt::GlobalColor colors[4];
for(int i=0; i<4; i++)
{
colors[i] = static_cast<Qt::GlobalColor>(2 + qrand() % 16);
}
}
QString QLoginDialog::getUser()
{
return m_user;
}
QString QLoginDialog::getPwd()
{
return m_pwd;
}
void QLoginDialog::Timer_timeout()
{
m_colors = getColors();
update();
}
QLoginDialog::~QLoginDialog()
{
}
运行结果:
