【问题标题】:Reading a password from std::cin从 std::cin 读取密码
【发布时间】:2010-11-27 15:49:37
【问题描述】:

我需要从标准输入读取密码并且希望std::cin 不回显用户键入的字符...

如何禁用 std::cin 的回显?

这是我目前正在使用的代码:

string passwd;
cout << "Enter the password: ";
getline( cin, passwd );

我正在寻找一种与操作系统无关的方法来执行此操作。 Here 在 Windows 和 *nix 中都有办法做到这一点。

【问题讨论】:

标签: c++ stl password-protection


【解决方案1】:

@wrang-wrang 的回答非常好,但没有满足我的需求,这就是我的最终代码(基于 this)的样子:

#ifdef WIN32
#include <windows.h>
#else
#include <termios.h>
#include <unistd.h>
#endif

void SetStdinEcho(bool enable = true)
{
#ifdef WIN32
    HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); 
    DWORD mode;
    GetConsoleMode(hStdin, &mode);

    if( !enable )
        mode &= ~ENABLE_ECHO_INPUT;
    else
        mode |= ENABLE_ECHO_INPUT;

    SetConsoleMode(hStdin, mode );

#else
    struct termios tty;
    tcgetattr(STDIN_FILENO, &tty);
    if( !enable )
        tty.c_lflag &= ~ECHO;
    else
        tty.c_lflag |= ECHO;

    (void) tcsetattr(STDIN_FILENO, TCSANOW, &tty);
#endif
}

示例用法:

#include <iostream>
#include <string>

int main()
{
    SetStdinEcho(false);

    std::string password;
    std::cin >> password;

    SetStdinEcho(true);

    std::cout << password << std::endl;

    return 0;
}

【讨论】:

  • gcc 在这里警告:/home/curtine/git/pub/sxx/src/sxx.cpp:在函数'void set_stdin_echo(bool)'中:/home/curtine/git/pub/sxx/ src/sxx.cpp:84:19: 错误:负整数隐式转换为无符号类型 [-Werror=sign-conversion] tty.c_lflag &= ~ECHO;
  • 我认为要禁用该警告
  • 就不回显方面而言,这是一个很好的答案,但我已否决了它,因为它将密码读入不安全的 std::string 中(参见例如stackoverflow.com/questions/5698002/…)。您是否会考虑将其修改为读入 char[]?在这种情况下,我很乐意推翻我的反对意见。
  • 另外,关于@ericcurtin 的评论,我发现&amp;= ~(0u | ECHO) 是一种避免警告的更好方法,而不是简单地禁用它。不过有趣的 API。 :-$
  • 只是提醒大家阅读,StackOverflow 不是专业的安全建议。也就是说,@nickform,您可以轻松地将 std::cin 替换为 char buffer[BUF_SIZE]; fgets(buffer, BUF_SIZE, stdin);,但正如 Eric 指出的那样,您需要安全地重写缓冲区,如果您要手动覆盖它,您也可以使用std::string。你不能做的事情是创建一个会为你自动完成的类(从 std::string 派生)。
【解决方案2】:

标准中没有这方面的内容。

在 unix 中,您可以根据终端类型写入一些魔术字节。

如果可用,请使用getpasswd

您可以 system() /usr/bin/stty -echo 禁用 echo,/usr/bin/stty echo 启用它(同样,在 unix 上)。

This guy explains不使用“stty”怎么办;我自己没试过。

【讨论】:

  • 我猜getpasswd 真的很有帮助。但我正在寻找一种方法来做到这一点,而不会再次出现操作系统黑魔法
【解决方案3】:

如果你不关心可移植性,你可以在VC中使用_getch()

#include <iostream>
#include <string>
#include <conio.h>

int main()
{
    std::string password;
    char ch;
    const char ENTER = 13;

    std::cout << "enter the password: ";

    while((ch = _getch()) != ENTER)
    {
        password += ch;
        std::cout << '*';
    }
}

wide characters 也有 getwch()。我的建议是您使用NCurse,它在*nix 系统中也可用。

【讨论】:

    【解决方案4】:

    只知道我有什么,您可以逐个字符读取密码,然后打印退格键(“\b”),也许还有“*”。

    【讨论】:

    • 如果有人将终端输出记录到文件中,那么整个密码将在那里。那么,这可能不是一个好主意。
    • 与记录所有按键的情况相同:)
    • 这是不安全的,也是个坏主意。依靠管道的另一端来确保自己的安全是不可接受的。并注意不要通过网络进行管道传输。并且记录输出!= 记录按键:您通常会将日志文件的读取用户权限授予更多的人,而不是那些有权在终端模拟器程序上写入,或者挂钩到终端或系统事件或键盘驱动程序的人。
    猜你喜欢
    • 2021-02-10
    • 2013-07-31
    • 2021-02-28
    • 2011-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-29
    相关资源
    最近更新 更多