保护IBM Lotus Domino Web服务器的安全:使用新的Internet锁定功能

Internet密码锁定使管理员可以为Lotus Domino应用程序(包括Lotus Domino Web Access)的用户设置Internet密码认证失败的阈值。 通过锁定在预定尝试次数内未登录的任何用户,此锁定有助于防止对用户Internet帐户的暴力攻击和字典攻击。 有关身份验证失败和锁定的信息在Internet锁定应用程序中维护,管理员可以在其中清除失败并解锁用户帐户。

但是请注意,此功能会受到拒绝服务(DoS)攻击。 DoS攻击是恶意用户明确阻止服务的合法用户使用该服务的攻击。 在Internet密码锁定的情况下,攻击者可能会故意阻止登录尝试,从而阻止合法的Internet用户登录Lotus Domino服务器。

Internet密码锁定有一些使用限制:

  • 您只能将Internet密码锁定与Web访问一起使用。 当前不支持其他Internet协议和服务,例如LDAP,POP,IMAP,DIIOP,IBM LotusQuickPlace®和IBM LotusSametime®。 但是,如果用于身份验证的密码存储在LDAP服务器上,则可以将Internet密码锁定用于Web访问。
  • 如果使用自定义DSAPI过滤器,则可能无法利用Internet锁定功能的功能,因为DSAPI过滤器是绕过LotusNotes®和Domino认证的一种方法。
  • 对于单点登录(SSO),启用了Internet密码锁定功能的Lotus Domino服务器也必须是发出单点登录密钥的服务器。 如果从另一个来源(例如,另一个Lotus Domino服务器或IBM WebSphere服务器)检索到此密钥,则即使启用了Internet密码锁定,SSO令牌在Lotus Domino服务器上也始终有效。

请记住,Internet锁定需要Lotus Domino 8服务器和Lotus Domino 8通讯簿模板。

配置Internet锁定

默认情况下,Lotus Domino服务器上未启用Internet锁定。 在本节中,我们记录了为在Lotus Domino服务器上启用Internet锁定而可以采取的步骤。

要使用配置设置启用Internet锁定,请按照下列步骤操作:

  1. 使用Lotus Notes客户端打开Lotus Domino目录。
  2. 单击配置-服务器-配置。
  3. 编辑默认服务器配置文档或单个服务器配置文档。
  4. 单击安全性选项卡。
    • 将选项“强制Internet密码锁定”更改为“是”。
    • 设置日志设置。 记录锁定和失败。
    • 设置默认最大尝试次数。
    指定在用户被锁定之前允许的最大错误密码尝试次数。 默认值为5。锁定用户后,必须解锁该用户帐户,此设置的任何新值对该用户生效。

    如果用户对于用户策略中的设置具有不同的值,则该值将覆盖服务器配置文档中的那个值。
  5. 设置默认的锁定到期时间。

    指定强制执行锁定的时间段。 在指定的时间段到期后,当用户下次尝试进行身份验证时,用户帐户将自动解锁。 此外,将清除所有失败尝试。

    注意:如果此值为0,则锁定不会自动过期。 该帐户必须手动解锁。
  6. 设置默认的最大尝试间隔。

    指定失败的密码尝试在锁定数据库中保留的时间长度,然后才能通过成功的身份验证将其清除。 默认值为24小时。

    此设置不适用于被锁定的用户。 如果用户被锁定,清除失败尝试和解锁帐户的唯一方法是手动,在Internet锁定数据库中或发生锁定到期时进行操作。

    注意:如果此值为0,则对于未锁定的给定用户,每次成功登录都会清除该用户的所有失败密码尝试。

    图1. Internet锁定设置
    互联网锁定设置
  7. 保存并关闭。
  8. 重新启动Lotus Domino服务器。

也可以使用安全策略配置Internet锁定。 这种方法使管理员可以仅对一部分用户强制执行Internet锁定。 请注意,安全策略可以覆盖服务器的Internet锁定设置。

要使用安全策略启用Internet锁定,请按照下列步骤操作:

  1. 打开Lotus Domino目录。
  2. 单击配置-策略-设置。
  3. 打开安全策略。 如果不存在,请创建一个新的安全策略。
  4. 单击Password Management选项卡,然后输入这些值,如图2所示:
    • 设置选项覆盖服务器的Internet锁定设置? 是的。
    • 将选项“允许的最大尝试次数”设置为5。
    • 将选项“锁定过期”设置为60分钟。
    • 将选项最大尝试间隔设置为1天。
    • 将所有设置设置为“强制”。
    图2.设置安全策略
    设定安全政策

配置安全设置后,可以将它们分配给策略,并且可以将策略分配给单个用户或组织单位。 有关设置策略的更多信息,请参考Lotus Domino Administration Help数据库 。 请注意,必须在服务器配置文档中启用Internet密码锁定,才能实施Internet密码锁定策略设置。 这种方法允许管理员为各个用户组设置不同的设置。

配置这些设置后,将创建一个inetlockout.nsf数据库。 该数据库记录并跟踪锁定的用户和失败的登录。 在支持Web的服务器之间复制此数据库,以确保锁定的用户对于整个基础结构保持锁定状态。 inetlockout.nsf数据库是从inetlockout.ntf数据库模板创建的。 应将所有用户都列为无权访问数据库。 只有Internet密码管理员才能访问此数据库。

图3显示了用户被锁定后收到的消息。 该消息与默认登录表单一起显示。 在本文的后面,我们将更改为自定义登录表单。

图3.锁定消息
锁定消息

inetlockout.nsf数据库还允许管理员跟踪哪些用户已被锁定。 管理员还可以选择解锁用户。 图4显示了Internet锁定数据库中可用的信息。 该数据库还可以记录所有用户登录失败。 当安全管理员尝试检测密码黑客尝试时,此事实可能会很有用。

图4. Internet锁定数据库
Internet锁定数据库

自定义登录表格

在本文的这一部分中,我们将讨论一个示例定制的登录表单。 该登录表单提供了改进的用户界面(UI)和密码重置功能。 我们使用新的登录表单创建了一个自定义数据库。 我们修改了domcfg.nsf,以将登录请求指向我们的自定义登录表单。

Lotus Domino Web服务器配置数据库的说明

缺省情况下,不创建Domino Web服务器配置数据库。 您可能需要使用domcfg5.ntf模板来创建此数据库。

要修改Domino Web服务器配置数据库,请按照下列步骤操作:

  1. 打开服务器上的domcfg.nsf数据库。
  2. 单击添加映射按钮。 在“应用于”字段中,输入“所有网站/整个服务器”。
  3. 在“目标数据库”字段中,输入包含自定义登录表单的数据库的名称。
  4. 在“目标表单”字段中,输入数据库中目标表单的名称。 在我们的示例中,数据库称为PwdMgt.nsf,表单称为CustomLoginForm。

    图5.设置“登录”表单映射
    设置“登录”表单映射
  5. 单击保存和退出按钮。
  6. 在服务器上重新启动HTTP任务。

现在,当用户请求需要身份验证的数据库时,他们将看到自定义的登录表单。

定制的登录表单如图6所示。它包括一个密码重置按钮。 用户在“用户ID”字段中输入用户ID并单击“密码重置”按钮后,他们会收到一封包含新密码的电子邮件。

图6.定制的登录表单
定制的登录表单

图7显示了密码重置后用户收到的电子邮件。

图7.密码重置的电子邮件通知
电子邮件密码重置通知

密码重置工具

以下示例代码可用于演示如何从浏览器客户端中的自定义登录窗口更新HTTP密码。 该代码并非旨在直接投入生产,但显然可以促进开发工作,并有可能缩短相关实现的开发生命周期。

本文提供的代码允许用户单击自定义密码管理应用程序中“自定义登录”窗口上的“密码重置”按钮。 “密码重置”按钮运行PwdQuery代理,该代理创建唯一的随机密码,更新Lotus Domino目录中的个人文档,并使用新的唯一密码创建并向用户发送电子邮件。

表1概述了示例代码中包含的设计元素。 作为示例代码提供的代理应该由运行它们的服务器签名。 该签名为代理提供了在服务器上运行的正确权限以及对通讯簿的适当访问权限。

表1.示例代码的设计元素
设计元素名称 类型 描述
自定义密码管理 应用 此元素是一个自定义NSF文件,其中包含“自定义登录”表单和运行大部分事务的代理。
CustomLogonForm 形成 此元素是一个自定义登录表单,位于密码管理(PwdMgt.nsf)Lotus Domino应用程序中。 如果需要,可以在Lotus Domino配置数据库中找到此功能和表单。 当HTTP认证请求发送到Lotus Domino服务器时,该表单将显示给用户。
重设密码 纽扣 重置密码按钮位于CustomLogonForm上,并显示给用户。 当用户单击“重置密码”按钮时,JavaScript™代码将构造一个调用PwdQuery代理的URL。
查询 代理商 该代理使用LotusScript®编写,并且执行以下操作:
  1. 从URL检索用户名。
  2. 创建一个新的随机密码。
  3. 在Lotus Domino目录中关联的“个人”文档上找到并更新HTTPPassword和HTTPPasswordChangeDate字段。
  4. 使用新密码向用户发送电子邮件。
  5. 向用户显示输出屏幕,告知用户密码已重置。

PwdQuery代理:调用

该代理将使用URL进行调用。 该URL必须包含附加在QueryString中的URL的用户名。 这是执行代理的示例URL:
/PwdMgt.nsf/PwdQuerySave?OpenAgent&QueryString=Scott Rice/ibm

PwdQuery代理:输入

代理程序的输入是要更新其HTTP密码的人员的用户名。 为了实现此示例代码,用户名必须是该用户的缩写Lotus Notes名称。 它使用URL中的QueryString方法传递给代理。 如果需要,可以将代理代码更改为映射到其他视图,或者可以在Lotus Domino目录中创建新视图,以便使用Lotus Notes通用名。

PwdQuery代理:输出

代理程序的输出向用户显示说明密码已成功更改为新的随机密码的文本,或者如果代理程序执行期间发生错误,则会在浏览器窗口中显示错误消息。

样例代码

这是我们为支持本文而编写的示例代码。

CustomLogonForm中的“密码重置”按钮

以下代码启动用户的密码更改。 当用户单击“密码重置”按钮时,将启动JavaScript changePwd()函数。

javascript:changePwd();

CustomLogonForm中的表单JS标头代码

此JavaScript函数位于Lotus Domino表单的JS标头中,并使用URL中的?OpenAgent运行PwdQuery代理。 此代码由“密码重置”按钮调用。

function changePwd(){
var uname = document.forms[0].Username.value;
window.location = '/PwdMgt.nsf/PwdQuery?OpenAgent&QueryString=' + uname;
}

PwdQuery:代理初始化代码

清单1中显示的代码是由执行大部分事务的changePwd()JavaScript函数调用的代理代码。 该代理创建一个随机密码,在Lotus Domino目录中的个人文档上设置密码以及日期和时间,然后使用新的HTTP密码向用户发送电子邮件。

清单1.代理初始化代码
Sub Initialize
%REM
Purpose - This agent is for demo/sample purposes only and is not intended to be 
implemented in a production environment.  This agent createsa random password and sets 
the HTTPPassword and HTTPPasswordChangeDate fields with appropriate values. Then an 
email is sent to the user with the new password.  Please note that it may take a few 
minutes for the user to use new password after the agent has be executed.

Input. Abbreviated Lotus Notes name that is used to look up the person document in 
the Lotus Domino Public Directory.

Output.  The Print statement in this agent writes to the browser and shows the user 
that the agent has been processed as the password has been changed.  The output of 
this agent is only a sample and is limited in nature but could be expanded on greatly.

Instantiated.  This is agent is to be executed by a URL with the user name of the 
person to have the password change appended to the URLusing  QueryString.  
The URL should conform to this standard for the agent to execute properly:
http://domain/PwdMgt.nsf/PwdQuerySave?OpenAgent&QueryString=Abbreviated Name
%END REM
	
' Setup the Agent Log
Dim errStr As String     'Error string variables
Dim agentLog As New NotesLog("Agent log")     'Used to write to the Agent Log
Call agentLog.OpenAgentLog
Call agentLog.LogAction("Entering the Initialize")
	
On Error Goto ErrorHandler
	
' Setup the variable to be used to process the Admin P Request
Dim session As New NotesSession     'Domino Session object
Dim dbDirectory As NotesDatabase     'Database object for the Domino directory
Dim db As NotesDatabase     'Database object for this database
Dim viewDirectory As NotesView	     'View object in the Domino Directory to look up 
the person document
Dim personDoc As NotesDocument     'Person document related to the User 
Name password to be changed
Dim userName As String     'User Name of the end user to be processed
Dim dirName As String     'Domino Directory file name (normally names.nsf)
Dim vwName As String     'View name used in the Domino Directory to 
look up the person document
Dim password As String     'New random password to be used on the 
Person document in the HTTPPassword field
Dim docContext As NotesDocument     'Web document used to get the 
QueryString / User Name variable
Dim queryString As String     'Variable from the URL that executes 
this agent containing the user name	
	
'set variables for the agent
Set docContext = session.DocumentContext
If Not(docContext Is Nothing) Then
	queryString = docContext.QUERY_STRING(0)
	agentLog.LogAction("QueryString = " + queryString)
Else
	agentLog.LogAction("There is no docContext for
	QueryString variable. 
	Must execute this agent from a URL with 
	'/PwdMgt.nsf/PwdQuerySave?OpenAgent&QueryString=Abbreviated Name'")
	errStr = "There is no docContext for QueryString variable. Must execute this 
	agent from a URL with 
	'/PwdMgt.nsf/PwdQuerySave?OpenAgent&QueryString=Abbreviated Name'"
	Goto ErrorHandler
End If
	
'get the username to be processed
userName = getUserName(agentLog, queryString)
	
'variables to run code below
dirName = "names.nsf"
vwName = "($VIMPeople)"
	
'create a unqiue password to be reset
password = createUniquePwd(agentLog)
	
'open the directory and the custom pwd change mgt tool
Set dbDirectory = session.GetDatabase("", dirName)
Set db = session.CurrentDatabase
	
If dbDirectory.IsOpen Then
	'set the vew to lookup the person document with
	Call agentLog.LogAction("Opened the directory")
	Set viewDirectory = dbDirectory.GetView(vwName)
		
	If Not(viewDirectory Is Nothing) Then
		Call agentLog.LogAction("Set the Directory View")		
			
		'set the person document in the view
		Call agentLog.LogAction("viewName is " + viewDirectory.Name)
		Set personDoc =  viewDirectory.GetDocumentByKey(userName, True)
			
	If Not(personDoc Is Nothing) Then
		Call agentLog.LogAction("Set the person document")
				
		'set the HTTP Password field to a unique random value
		personDoc.HTTPPassword = password				
				
				
		'set the date time value that the HTTP Password was set
		personDoc.HTTPPasswordChangeDate = Now
				
				
		'save the person document
		Call personDoc.Save(True, False)		
		Call agentLog.LogAction("Saved the persondocument")
				
		'send email using the DisplayName field in the person document
		Dim emailDoc As NotesDocument				
		Dim sendToName As String
		sendToName = personDoc.InternetAddress(0)
		Call agentLog.LogAction("SendTo:  " + sendToName )	
				
		Set emailDoc = New NotesDocument( db )
		Call agentLog.LogAction("Created new email document")
				
		'create the email fields and associated values
		emailDoc.Form = "Memo"
		emailDoc.SendTo = sendToName
		emailDoc.Subject = "URGENT:  HTTP Password Change Request"
		emailDoc.Body = "Your HTTP Password was changed to: " + password
		Call agentLog.LogAction("Set fields on email document")
				
		'route the document to the end user
		Call emailDoc.Send( False )
		Call agentLog.LogAction("Sent the email to " + sendToName)
				
	Else
		'couldn't open the person document
		errStr = "Could not get the person document in the Directory.  Probably 
		need to use the Abbreviated name instead of Common Name."
		Call agentLog.LogAction("Could not get the person document in the 
		Directory.  Probably didn't use the Abbreviated name.")
		Goto ErrorHandler
	End If		
			
Else
	'couldn't open the view in the directory
	errStr = "Could not get the view in the directory"
	Call agentLog.LogAction("Could not get the view in the directory")
	Goto ErrorHandler
End If
		
Else
	'could not open the Domino Directory
	errStr = "Could not open the Domino Directory"
	Call agentLog.LogAction(errStr)
	Goto ErrorHandler
End If
	
' Close out the Agent
Call agentLog.LogAction("Existing Intialize")
Call agentLog.Close
	
'Print out to the browser to notify the end user
Print "Password has been changed for " + UserName + ".  Please check your 
email via a Notes Client for the password."
	
Exit Sub
	
ErrorHandler:
	If errStr = "" Then
		errStr =  "Error in Initialize: " & Err() & ": " & Error()
	End If
	
	Call agentLog.LogAction(errStr)
	Call agentLog.Close
	
	Print "An error occured please check the Agent Log for details.  
	<br><br> Description of what occured is: <br>" + errStr
	
End Sub

PwdQuery代理:createUniquePwd函数代码

此LotusScript函数通过在LotusScript中使用Evaluate利用@Unique @Function来创建新的唯一密码。 返回值是调用此函数的初始化子例程的新的唯一密码。 参见清单2。

清单2. createUniquePwd函数代码
Function createUniquePwd(agentLog As NotesLog) As String
	
Call agentLog.LogAction("entering createUniquePwd function")
	
Dim pwdunique As Variant     'contains the new unique password to be created
from the @Unique @function
Dim password As String			'contains the string form of the unique password
Dim i As Integer						'counter
Dim r As String						'used for string parsing
Dim l As String						'used for string parsing
Dim errStr As String				'used for error handling
	
On Error Goto ErrorHandler
	
'create the unique password for the end user
pwdunique = Evaluate("@Unique")
password = pwdunique(0)
Call agentLog.LogAction(password)
	
'parse the password to remove the - character
i = Instr(password, "-")
Call agentLog.LogAction(i)
l = Left(password, i - 1)
r = Right(password, i + 1)
Call agentLog.LogAction("l = " + l )
Call agentLog.LogAction("r = " + r )
	
'return the new unique password back to the main function
createUniquePwd = l + r
	
Call agentLog.LogAction("exiting createUniquePwd function")
	
Exit Function
	
ErrorHandler:
	
	errStr =  "Error in createUniquePwd: " & Err() & ": " & Error()
	Call agentLog.LogAction(errStr)
	
End Function

PwdQuery代理:getUserName函数代码

此LotusScript函数由代理的initialize子例程调用,并返回要为其更改密码的用户的实际用户名。 查询字符串例如以&QueryString = Scott%20 Rice / ibm的形式传入,并在示例Scott Rice / ibm中输出。 参见清单3。

清单3. getUserName函数代码
Function getUserName(agentLog As NotesLog, queryString As String) As String
	
	Dim i As Integer				'used as a counter
	Dim strTemp As String	'used to get the username as a string without %20 
	and replaced with blank spaces
	Dim qStr As Variant		'used with the @ReplaceSubString @function to 
	replace any %20 's in the string with black spaces
	Dim errStr As String		'used for error handling
	
	On Error Goto ErrorHandler
	
	'retrieve just the username from the QueryString
	agentLog.LogAction(queryString + " - in getUserName function")
	i = Instr(queryString, "=")
	agentLog.LogAction("i = " + Str(i))
	queryString = Right(queryString, Len(queryString) - i)
	
	'used for testing the @function so that the agent log
	agentLog.LogAction(queryString + " - In getUserName")
	agentLog.LogAction("@ReplaceSubString(""" + queryString + """, ""%20"", "" "")")
	
	'use the @ReplaceSubString @function to replace the %20 with black spaces
	qStr = Evaluate("@ReplaceSubString(""" + queryString + """; ""%20""; "" "")" )
	strTemp = qStr(0)
	agentLog.LogAction(strTemp + " - after Evaluate")
	
	'assign the name with appropriate blanks as a string
	queryString = strTemp
	
	'return the user name back to the main routine
	getUserName = queryString
	
	agentLog.LogAction("exiting getUserName function")
	
	Exit Function
	
ErrorHandler:
	
	errStr =  "Error in getUserName: " & Err() & ": " & Error()
	Call agentLog.LogAction(errStr)
	
End Function

PwdQuery代理:deleteLockoutRecord函数代码

我们在此代理中包含此LotusScript子例程(如清单4所示)作为示例代码,但未在示例中调用它。 如果用户超过最大尝试登录次数,并且为该用户创建了锁定记录,则此代码将删除该锁定用户应用程序(interlockout.nsf)中该用户的所有锁定文档。 目前尚未在代理中调用此例程,但是您可以根据需要将其包含在Initialize子例程中。

清单4. deleteLockoutRecord函数代码
Sub deleteLockoutRecord(session As NotesSession, agentLog As NotesLog, 
UserName As String)
%REM
This subroutine was included as a sample if someone wanted to delete the Locked Out 
records.  Just add this routine to the main 
Initialize of this agent and pass in the appropriate parameters	
%END REM
	
	Dim db As NotesDatabase     'dabase object for the Internet Locked Out database
	Dim view As NotesView     'view object to loop through the document in the 
	Locked Out database
	Dim doc As NotesDocument     'document object for each document while looping 
	through the document of the view
	Dim tmpdoc As NotesDocument     'temporary document set if there is a match so
	it can be deleted after the next document has been retrieved
	Dim item As NotesItem     'object for the ILUserName field on the document 
	which holds the users' name
	Dim notesname As NotesName     'object to change the name to abbreviated
	Dim abbrevName As String     'string that represents the appreviated user 
	name on the Locked Out document
	Dim deleteDoc As Boolean     'boolean true or false to flag a document to 
	be deleted
	Dim viewName As String     'variable that references the view name in the 
	Locked Out database
	Dim dbFileName As String     'variable that references the file name of the 
	Locked Out database
	Dim fieldName As String     'variable that references the field name 
	in the locked out document
	Dim errStr As String     'used in error handling
	
	On Error Goto ErrorHandler
	
	'set the variables
	dbFileName = "inetlockout.nsf"	
	viewName = "Locked Out Users"
	fieldName = "ILUserName"
	
	'set up the objects to be used in the subroutine
	Set db = session.GetDatabase("", dbFileName)
	agentLog.LogAction("opened the Locked Out database")
	Set view = db.GetView(viewName)
	agentLog.LogAction("opened the view " + viewName)
	Set doc = view.GetFirstDocument
	If doc Is Nothing Then
		agentLog.LogAction("There are no Locked Out documents to be processed")
	Else
		agentLog.LogAction("opened the first document")
	End If
	deleteDoc = False
	
	'loop through the view and delete any documents with the user name passed in
	While Not( doc Is Nothing )
		'get the user name on the Locked Out document
		Set item = doc.GetFirstItem( fieldName )
		'change it to an abbreviated form
		Set notesname = session.CreateName(item.Text)
		abbrevName = notesname.Abbreviated
		agentLog.LogAction("processing for: " + abbrevName)
		
	'check to see if there is a match and if true then save the document and flag 
	that this needs to be deleted
	If Ucase(UserName) = Ucase(abbrevName) Then
		agentLog.LogAction(Ucase(UserName) + " = " + Ucase(abbrevName))
		Set tmpdoc = doc
		deleteDoc = True
		agentLog.LogAction("deteleDoc = " + Str(deleteDoc))
	End If
		
		'get the next document in the view
		Set doc = view.GetNextDocument( doc )
		
		'delete the document from the Locked Out database
		If deleteDoc Then
			Call tmpdoc.Remove(True)
			Set tmpdoc = Nothing
			deleteDoc = False
		End If
		
	Wend
	
	Exit Sub
	
ErrorHandler:
	
	errStr =  "Error in deleteLockedOutRecord: " & Err() & ": " & Error()
	Call agentLog.LogAction(errStr)
	
End Sub

结论

在本文中,我们讨论了Lotus Domino 8的Internet密码锁定功能。我们回顾了此功能的功能,并讨论了如何为Lotus Domino 8服务器配置它。 我们还讨论了如何创建自定义登录表单并提供了示例密码重置工具。 我们提供了一个保护和自定义Web界面的起点。 在“资源”部分列出的先前文章中,我们讨论了Lotus Domino Web安全性,并提供了一个示例Lotus Domino Web服务器实现的案例研究。 本文添加了另一种提供Internet安全性的方法,该方法不需要以前版本中的自定义DSAPI筛选器。


翻译自: https://www.ibm.com/developerworks/lotus/library/domino8-lockout/index.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值