使用base64编码,服务器发送"Username","Password",客户端回答也是base64

解决方案 »

  1.   

    能说的详细一点儿吗?我有一个SMTP类,里面也有base64类,但好像没有发送身份验证的函数:(
      

  2.   

    rfc1891 - SMTP
    我也有一个SMTP的类,不过也不支持验证。
      

  3.   

    看rfc2554.下面是个会话的例子1 S: 220 smtp.example.com ESMTP server ready
    2 C: EHLO jgm.example.com
    3 S: 250-smtp.example.com
    4 S: 250 AUTH CRAM-MD5 DIGEST-MD5
    5 C: AUTH FOOBAR
    6 S: 504 Unrecognized authentication type.
    7 C: AUTH CRAM-MD5
    8 S: 334
    9 PENCeUxFREJoU0NnbmhNWitOMjNGNndAZWx3b29kLmlubm9zb2Z0LmNvbT4=
    10 C: ZnJlZCA5ZTk1YWVlMDljNDBhZjJiODRhMGMyYjNiYmFlNzg2ZQ==
    11 S: 235 Authentication successful.AUTH命令
       
       AUTH机制 [初始化响应]   参数:
         判别是一个SASL认证机制的字符串。     可选的由base64编码的响应。   约束:
             在一个AUTH命令完整结束后,本次会话就不再有其他的AUTH命令涉及了。就是说,在一个成功的AUTH命令后,SMTP服务器用503标识的回应来拒绝任何以后的         AUTH命令。         在一个邮件传输过程中发出的AUTH命令是不被容许的。   讨论:
             AUTH命令显示了一种和邮件服务器间的安全认证机制 。如果邮件服务器支持这种认证机制,它就会执行一个认证协议交互来认证并识别邮件用户。作为可选的情况,他也会忽略这以后后协议交互的一个安全层。如果服务器并不支持所需要的认证协议,就会用504的回答来拒绝这个AUTH命令。         认证协议交互过程由一系列由认证机制定义的邮件服务器端的命令和邮件客户端的响应组成。         一个邮件服务器端命令,或者所谓一个准备好响应,是一个334起头的,包含用base64编码的字符串文本。邮件客户端也同样由包含了用base64编码的字符串。如果邮件客户端希望可以取消一个进行中的认证交互过程,它会发出一个仅包含一个字符"*"命令行,邮件服务器端一旦收到这样的一个回答后,必须发一个501标识的回答,而后拒绝AUTH命令。
             对AUTH命令来说,可选的初始化响应建议是用来在使用认证机制时保持一个往返的回程,认证机制的定义中此建议不发送任何数据。当初始化响应部分用在这种机制时,开始的空的发起命令不被送到客户端,并且服务器端使用的数据也好象是发送来响应一个空的命令。它发送一个零长度的初始化回答作为一个"="符号。如果客户端在认证机制的AUTH命令响应中使用初始化建议,客户端就在初始化命令中发送响应的数据,服务器端用535回答来拒绝AUTH命令。         如果不能对参数用base64解码,就用501回答来拒绝AUTH命令,如果服务器拒绝认证数据,它应该用535的回答(可以带其他详细的特殊错误代码,比如在第6节所列的代码中的一个)来拒绝AUTH命令。如果客户端成功完成了认证交互,SMTP服务器就应该返回一个235的响应。        
             本SASL协议梗概中描述的服务名称是SMTP.         如果一个安全层通过了SASL认证交换,随着作为终止客户端认证交换的CRLF(回车换行),这个安全层立即有效。在安全层起作用后,其上的SMTP协议被复位到初试状态(这个SMTP状态是在服务器发出一个220服务准备好的消息后开始的)。接着服务器就会放弃所有来自客户端的知识,例如,不是获得自SASL协商本身的EHLO命令的参数。客户端也会放弃所有来自服务器端的知识,例如,不是获得自SASL协商本身的SMTP扩展服务(这里假设一个客户端可以比较认证前后的建议的SASL机制的列表,从而检测主动down-negotiation攻击)。客户端应该发出一个EHLO命令,此命令作为使一个安全层有效的认证协商成功后的第一个命令。 
             服务器并不被要求一定支持任何特定的认证机制,同样认证机制要不要求必须支持某种安全层。
             一旦一个AUTH命令失败,客户端可以通过发出另外一个AUTH命令来尝试其他一种认证机制。
             一旦一个AUTH命令失败,服务器端的行为就好象客户端从没有发出那次AUTH命令一样。
             
             base64编码的字符串一般可以有任意长度。客户端和服务器端都应该可以支持那些由认证机制产生的合法的任意长的请求和响应字符串,而不依赖于服务器或者客户端的、可能存在于协议实现的某些方面的行长度的限制。
      

  4.   

    下面这篇文章是我找到的一篇文章,写的比较详细了。
    <br />当然前提是你需要有那个N多人用的CSMTP.CPP和CSMTP.H
    <br />把下文的身份验证部分加到CSMTP.CPP中再稍微调试一下就OK了。自己琢磨一下,更有成就感。
    <br />
    <br />
    <br />本站原创:KKnD
    <br />
    <br />相关资料:Simple Mail Transfer Protocol (SMTP) RFC2821(英文)
    <br />
    <br />  有一段时间很多地方都在讨论如何写一个发送邮件的程序的问题,其实一个邮件发送程序
    <br />没有想象的那么难做,现在先简单讲一下怎样连接邮件服务器以及怎样做验证的过程。
    <br />
    <br />  首先创建一个socket,接下来连接你想要连接的发件服务器,连接上之后发送helo命令,
    <br />该命令的语法是helo <你的域名|你的IP>,之后分析接收到的返回串,返回字符串的前三位
    <br />是状态码,helo命令如果返回250就可以继续,否则就是有错误。接下来发送auth login命
    <br />令,如果返回码不是334,那么就是不需要验证,否则,注意!要将你的用户名和密码用
    <br />BASE64编码算法编码后分别发送过去,而不是直接发送。如果服务器返回状态码235就是验证
    <br />通过,不然就是用户名/密码有错误。下面是我连接smtp.263.net的过程(s:服务器 c:客户
    <br />端):
    <br />
    <br />s:220 smtp.263.net ESMTP
    <br />c:HELO mylocalhost
    <br />s:250 smtp.263.net
    <br />c:auth login
    <br />s:334 VXNlcm5hbWU6
    <br />c://我的用户名(已编码)
    <br />s:334 UGFzc3dvcmQ6
    <br />c://我的密码(已编码)
    <br />s:235 Authentication successful
    <br />
    <br />源代码:
    <br />[连接] 
    <br />BOOL CSmtp::Connect()
    <br />{
    <br />CString sHello;
    <br />TCHAR local_host[80]; // Warning: arbitrary size
    <br />if(m_bConnected) return TRUE;
    <br />
    <br />try {
    <br />// This will be deleted in Disconnect();
    <br />response_buf = new TCHAR[RESPONSE_BUFFER_SIZE];
    <br />if(response_buf == NULL) {
    <br />m_sError = _T("Not enough memory");
    <br />return FALSE;
    <br />}
    <br />} catch(CException* e) {
    <br />response_buf = NULL;
    <br />m_sError = _T("Not enough memory");
    <br />delete e;
    <br />return FALSE;
    <br />}
    <br />
    <br />if(!m_wsSMTPServer.Create()) {
    <br />m_sError = _T("Unable to create the socket");
    <br />delete response_buf;
    <br />response_buf = NULL;
    <br />return FALSE;
    <br />}
    <br />if( !m_wsSMTPServer.Connect(m_sSMTPServerHostName, m_nPort)) {
    <br />m_sError = _T("Unable to connect to server");
    <br />m_wsSMTPServer.Close();
    <br />delete response_buf;
    <br />response_buf = NULL;
    <br />return FALSE;
    <br />}
    <br />if(!get_response(CONNECT_SUCCESS)) {
    <br />m_sError = _T( "Server didn’t respond" );
    <br />m_wsSMTPServer.Close();
    <br />delete response_buf;
    <br />response_buf = NULL;
    <br />return FALSE;
    <br />}
    <br />gethostname(local_host, 80);
    <br />sHello.Format(_T( "HELO %s\r\n" ), local_host);
    <br />m_wsSMTPServer.Send((LPCTSTR)sHello, sHello.GetLength());
    <br />if(!get_response(GENERIC_SUCCESS)) {
    <br />m_wsSMTPServer.Close();
    <br />delete response_buf;
    <br />response_buf = NULL;
    <br />return FALSE;
    <br />}
    <br />m_bConnected = TRUE;
    <br />return TRUE;
    <br />}
    <br />
    <br />[验证]
    <br />BOOL CSmtp::Auth()
    <br />{
    <br />CString sAuth;
    <br />if(!m_bConnected) return FALSE;
    <br />
    <br />sAuth.Format(_T( "auth login\r\n" )); //construct auth quest
    <br />m_wsSMTPServer.Send((LPCTSTR)sAuth, sAuth.GetLength());
    <br />if(!get_response(AUTHQUE_SUCCESS)) {
    <br />m_sError="SMTP server with no auth";
    <br />m_bAuthed=TRUE;
    <br />return TRUE;
    <br />}
    <br />
    <br />sAuth.Empty();
    <br />
    <br />sAuth.Format(_T( "%s\r\n" ), m_sSMTPUser); //is an string encoded with CBASE64
    <br />m_wsSMTPServer.Send((LPCTSTR)sAuth, sAuth.GetLength());
    <br />if(!get_response(AUTHQUE_SUCCESS)) {
    <br />m_sError="Unknown Error";
    <br />m_wsSMTPServer.Close();
    <br />delete response_buf;
    <br />response_buf = NULL;
    <br />return FALSE;
    <br />}
    <br />
    <br />sAuth.Empty();
    <br />
    <br />sAuth.Format(_T( "%s\r\n" ), m_sSMTPPass); //is an string encoded with CBASE64
    <br />m_wsSMTPServer.Send((LPCTSTR)sAuth, sAuth.GetLength());
    <br />if(!get_response(AUTH_SUCCESS)) {
    <br />m_wsSMTPServer.Close();
    <br />delete response_buf;
    <br />response_buf = NULL;
    <br />return FALSE;
    <br />}
    <br />m_bAuthed = TRUE;
    <br />return TRUE;
    <br />}
    <br />
    <br />
    <br />当上面的过程完成后,就完成了连接和验证的工作,可以开始准备发送邮件了。首先要使用的
    <br />是MAIL FROM:命令,格式"MAIL FROM: <发件人地址>",正常的返回码是250;这里要说的是有时上述命令会返回一个错误:553 Authentication is required to send mail as 
    <br />[email protected]。出现这样的错误的原因是MAIL FROM发送过去的发件人地址里面包含的用户名
    <br />和你登陆发件服务器时使用的用户名不同,只需将二者统一就行了。接下来是RCPT TO:命令,
    <br />告诉服务器你想发给谁,格式和返回码同MAIL FROM。然后是DATA命令,没有参数,返回码
    <br />354;该命令送到之后就可以发送信件的内容了,内容结束的标志是<CRLF>.<CRLF>,用字符
    <br />串表示就是"\r\n.\r\n"。最后退出服务器的命令是QUIT,无参数,返回码221。
    <br />
    <br />c:MAIL FROM: [email protected]
    <br />s:250 smtp.263.net
    <br />c:RCPT TO: acesee.263.net
    <br />s:250 smtp.263.net
    <br />c:DATA
    <br />s:354 Start mail input; end with .
    <br />c://信件正文
    <br /> 
    <br />c:<CRLF>.<CRLF>//正文结束
    <br />s:250 smtp.263.net
    <br />c:QUIT
    <br />s:221 Bye
    <br />
    <br />  源代码我就不在这里写了,太多了,请点击此处或到VC版下载仓库下载吧。
    <br />
    <br />