在上一期的文章中,我们已经了解了如何利用Qt开发一个基本的P2P聊天系统,并对服务端的用户管理和客户端的网络交互、音视频处理等模块进行了代码实践。
不过光有基本的通信功能还远远不够,要想开发出一款值得信赖的聊天应用,我们还必须重点关注系统的安全性和可靰性这两大核心需求。今天,我们就来全方位剖析一下在P2P架构中如何实现这两方面的技术保障。
一、安全性----坚不可摧的数据防线
1、用户认证
对于任何网络应用,用户身份认证都是安全防护的第一道防线。我们的聊天系统中也不例外,需要为每个用户分配唯一的账号密码,并在服务端存储这些认证信息。
// server.h
class UserManager : public QObject
{
Q_OBJECT
public:
// 注册新用户
void addUser(const QString& username, const QString& password);
// 检查用户凭据
bool checkCredential(const QString& username, const QString& password) const;
private:
// 用户名->密码哈希(SHA-256)
QHash<QString, QByteArray> m_credentials;
};
// server.cpp
void UserManager::addUser(const QString& username, const QString& password)
{
QByteArray pwdHash = QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Sha256);
m_credentials.insert(username, pwdHash);
}
bool UserManager::checkCredential(const QString& username, const QString& password) const
{
QByteArray pwdHash = QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Sha256);
return m_credentials.value(username) == pwdHash;
}
这里我们在UserManager
中使用QHash
存储所有注册用户的凭据。但与存明文密码不同的是,我们对用户密码进行了SHA-256算法的哈希加密,只存储哈希值而不是明文。
登录时,客户端将用户输入的账号密码传给服务器,服务器重新计算密码的哈希值,并与存储的哈希值对比,只有完全匹配才认证通过。这样即使服务器数据库被攻破,窃取到的也只是不可逆的哈希值,用户密码的安全性也得到了保障。
2、通信加密
用户认证环节保证了系统的入口安全,但是对于正式建立的通话会话,我们也需要对传输数据进行端到端加密。否则即使会话建立的过程是安全的,但数据在网络传输途中一旦被截获,通话隐私也将泄露。
// client.h
class P2PClient : public QObject
{
Q_OBJECT
...
public slots:
void startCall(const QString& peer);
void sendData(const QByteArray& data);
private:
QCryptographicHash m_crypto;
QByteArray m_sessionKey; // 会话密钥
QString m_peer; // 通话对象
...
};
// client.cpp
void P2PClient::startCall(const QString& peer)
{
// 生成会话密钥
m_peer = peer;
m_sessionKey = m_crypto.hash((peer + QUuid::createUuid().toByteArray()), QCryptographicHash::Sha256);
// 发起呼叫,并传递会话密钥