- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
经过一天的漫长编程,我想发布一些对其他人有用的东西。
几天前,我想知道如何使用正确的过程处理JPasswordField
的方法getPassword()
,以将值传递给服务器并获得答案。
这是一个问题:
如何安全地从JPasswordField
正确获取值并处理该值以使用服务器创建登录过程?
最佳答案
这是我达成的解决方案。
首先,我确定了足以达到我的目的的安全登录过程,我不想向服务器发送普通密码,也不想(显然)在数据库中存储普通密码。
首先要说的是,保护密码的好方法是永远不要以简单易懂的形式在网络上交换密码,这显然是因为可能存在“中间人”,简而言之就是有人以他们通往服务器的方式阅读您的消息。
密码需要进行哈希处理,这意味着密码会转换为很长的十六进制字符序列。哈希的好处是(希望)是单向的。您不能散列密码。
有很多算法可以做到这一点,我选择SHA256。
然后将密码散列,但是仅在我们之间,这还不够。如果黑客能够窃取该散列,则可以采用某些技术使他成功地对其进行“翻译”。只是为了在他的方程式中添加一个变量,并使他的生活更艰难,我们可以在对哈希值进行哈希处理之前在密码中添加盐。盐是一串字符串,它被添加到我们想要的密码的任何位置。这样可以避免基于字典和最常用密码的某种攻击。
但是,如果比我受过更好培训的黑客无法读取密码,我该怎么办?
答案很简单,我不必这样做。
但是要了解这一点,我们需要在“注册过程”中稍作停留,即将新用户添加到我的数据库中的那一刻。就是这个:
客户端要求服务器发送昵称进行注册。
服务器用令牌(密码的盐)来回答。
客户端对密码加盐,对其进行哈希处理,然后将其发送回服务器。
现在,服务器收到了一些无法读取的内容,因此没有安全问题,并将其与昵称和盐一起存储。加盐的哈希密码是“公共密码”。
因此,登录过程将如下所示:
客户端要求服务器登录
服务器用盐回答
客户端对密码进行盐析,然后对其进行哈希处理,然后将其发送回服务器。
服务器将共享机密与接收到的字符串进行比较。如果它们相等,则允许用户登录。
这应该很好,但是在这种情况下,如果黑客知道共享密钥可以毫无问题地访问服务器,因为这样做,我们只是更改了密码,使密码不可读,但仍然可以直接使用。
为了避免这种行为,我们只需要在我们的链中添加一个段落:
客户端要求服务器登录
服务器用盐和随机会话盐回答
客户端对密码加盐,然后对其进行哈希处理。在这一点上,它再次使散列盐化并重新散列。然后,它将哈希过的哈希过的哈希过的密码发送回服务器
服务器获取共享机密,将其与随机会话盐混合,然后进行哈希处理。如果两个字符串相等,则允许用户登录。
既然过程很清楚,我们有一个要解决的问题。如果我处理任何类型的String,它都可以在内存中保留很长时间,因此,如果我将密码放入String中,则可以很长时间以纯格式读取。这对我们来说不是那么好,但是我们并不是第一个考虑它的人,java确实创建了一种避免该密码持续存在的方法。解决方案是使用字符数组。这是因为即使阵列保留在内存中,其数据也会在内存中无序分布,并且很难重新创建原始密码。
重新发明热水?是的,只需在JPasswordField中使用getPassword()方法。
但这对于新手来说是相当困难的。我们得到一个char []数组,对于一个不是专家的人来说很奇怪。
我们首先想到的是将数组转换为纯字符串.......
但是,这正是我要避免的。所以我需要按原样处理数组。
然后,我们需要一种对密码进行加盐和哈希处理的方法,结果可能是这样的:
public static String digestSalted(String salt, char[] password) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
ArrayList<Byte> list = new ArrayList<Byte>();
for (int i = 0; i < password.length; i++) {
//String ch = String.valueOf(password[i]);
//byte[] b = ch.getBytes();
//for (int j = 0; j < b.length; j++) {
// list.add(b[j]);
//}
list.add((byte)password[i]);
}
byte[] saltInBytes = salt.getBytes();
byte[] toBeHashed = new byte[(saltInBytes.length + list.size())];
for (int i = 0; i < saltInBytes.length; i++) {
toBeHashed[i] = saltInBytes[i];
}
for (int i = saltInBytes.length; i < list.size() + saltInBytes.length; i++) {
toBeHashed[i] = list.get(i - saltInBytes.length);
}
md.update(toBeHashed);
byte byteData[] = md.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
String hex = Integer.toHexString(0xff & byteData[i]);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
public void login(String nickname, char[] password) {
if (cl == null) {
throw new RuntimeException();
}
long s = Sys.getTime();
cl.send("NICK " + nickname);
IncomingMessage reply = null;
try {
reply = this.mh.getMessage(); //The response to NICK msg
if (reply.getCommand().equalsIgnoreCase("LOGIN")) {
ArrayList<String> params = reply.getParams();
String accountSalt = params.get(0);
String randomSalt = params.get(1);
try {
String sharedSecret = SHAHash.digestSalted(accountSalt, password);
String saltedSharedSecret = SHAHash.digestSalted(randomSalt, sharedSecret);
if (saltedSharedSecret != null) {
cl.send("PASS " + saltedSharedSecret);
reply = this.mh.getMessage();
if (reply.getCommand().equalsIgnoreCase("WELCOME") && reply.getParams().get(0).equals(nickname)) {
// ************ LOG ************ //
LOG.config("Logged in.");
// ***************************** //
this.running = true;
this.loggedIn = true;
mh.startExecutor();
LOG.config("Time passed: " + (Sys.getTime() - s));
mh.startGame();
} else {
// ************ LOG ************ //
LOG.warning("A problem has occured while trying to login to the server.");
// ***************************** //
JOptionPane.showMessageDialog(null, "Error while logging to the server, shutting down.\n- ERROR 006 -");
System.exit(0);
}
}
} catch (NoSuchAlgorithmException e) {
// ************ LOG ************ //
LOG.warning("Error while SHA hashing the password, shutting down.");
// ***************************** //
JOptionPane.showMessageDialog(null, "Error while SHA hashing the password, shutting down.\n- ERROR 005 -");
System.exit(0);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.mh.getMessage()
是一种阻塞方法,这意味着线程将等到队列中的某些内容可用后再尝试得到它。
关于java - 使用JPasswordField并使用getPassword +服务器登录过程处理密码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18501164/
Internal Server Error: /admin/account/customuser/add/ Traceback (most recent call last): File "C:\
有问题!虽然我发现几乎相似的线程但没有帮助:( 我编写了一个 php 脚本来从我的 MySQL 数据库中获取注册用户的数量。该脚本在我的本地主机上运行良好;它使用给定的用户名、密码和主机名,分别是“r
我正在做一项基于密码的作业,我将 key 和消息放在单独的数组中。我想创建第三个数组,其中包含围绕消息大小的 key ,如下所示: message keykeyk 我已经在这个问题上苦苦挣扎了一段时间
我的几个客户要求我实现图形密码检查器,例如 关于如何实现这种 UI 有什么想法吗? 最佳答案 试着看看这个:https://code.google.com/p/android-lockpattern/
我正在使用 MAMP,每次登录 phpMyAdmin 时,都会收到以下错误/警告消息: the configuration file now needs a secret passphrase (bl
我正在尝试通过将 Visual Studio 2013 连接到我的测试机来调试 WDF 驱动程序。它创建一个名为 WDKRemoteUser 的用户,并在进行测试时尝试自动登录。有人知道这个用户的密码
使用具有指定用户名和密码的 SVN 提交。我希望服务器抛出错误;所以我可以告诉我的用户他/她的密码错误。 相反,在使用错误密码提交后: svn commit "test_file.txt" --use
我正在尝试实现 friend 推荐。 它从节点“你”开始。而且,我想找到节点“安娜”。 换句话说,这是我的两个或更多 friend 共同认识的人。上面的示例节点是 Anna。 如果您的帮助,我将不胜感
我都尝试过 wget --user=myuser --password=mypassword myfile 和 wget --ftp-user=myuser --ftp-password=mypass
我的一位用户提示说,每当他尝试使用默认管理界面(Django 的管理员)添加新用户(auth.User)时,新用户名和密码都会自动填充他自己的。 问题是他在登录时要求 Firefox 记住他的用户名/
我们正在开发一款应用(当然)用于应用购买 (IAP)。我已完成指南中的所有操作以启用 iap,并且一切正常,直到我想要购买为止。 部分代码: MainViewController.m -(vo
我试图创建两个可选匹配项的并集(如下所示),但我得到的不是并集,而是两者的交集。我应该如何更改此查询以获得所需的联合? optional match (a:PA)-[r2:network*2]-(b:
我想将Ansible用作另一个Python软件的一部分。在该软件中,我有一个包含其用户名/密码的主机列表。 有没有一种方法可以将SSH连接的用户/密码传递给Ansible ad-hoc命令或以加密方式
嗨,我在使用xampp的Apache Web服务器上收到错误500。直到我使用.htaccess,.htpasswd文件,错误才出现。我搜索了,但找不到语法错误。我只有1张图片和要保护的索引文件。以下
我一直使用它来编辑用户帐户信息: $this->validate($request, [ 'password' => 'min:6', 'password_confirmation'
我需要使用InstallUtil来安装C# Windows服务。我需要设置服务登录凭据(用户名和密码)。这一切都需要默默地完成。 有没有办法做这样的事情: installutil.exe myserv
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a software
如果我有一个随机的、16 个字符长的字母数字盐(不同大小写),它是为每个用户生成和存储的,我是否还需要一个站点范围的盐? 换句话说,这样好吗? sha1($user_salt . $password)
我正在开发一个空白程序,该程序将允许用户创建一个帐户,以便他们可以存储其余额和提款/存款。用户输入用户名和密码后,如何存储这些信息以便用户可以登录并查看其余额?我不一定要尝试使其非常安全,我只是希望能
我正在尝试寻找一种通用方法来搜索没有链接到另一个节点或节点集的节点或节点集。例如,我能够找到特定类型(例如 :Style)的所有节点,这些节点以某种方式连接到一组特定的节点(例如 :MetadataR
我是一名优秀的程序员,十分优秀!