电子公文传输系统安全性设计与实现

一、系统概述

我们的电子公文传输系统一共由16个网页组成:

建议路径全英文,否则会出现错误。

1.login.jsp

login.jsp是公文传输系统的首页,这一部分主要以前端的设计为主,这里就不详细阐述了。最主要的是在这个页面要把用户输入的账号密码传入后端。

2.register.jsp

register.jsp是公文传输系统的注册界面,用户在login.jsp中点击注册后便跳转至该页面。用户在注册时需要选择自己注册的身份,并且注册完的用户必须要等待管理员审批,审批通过即可正常登录。

3.index.jsp、left.jsp、head.jsp

index.jsp是登陆的主界面,左边是left.jsp界面,有六个功能栏。每个角色仅能访问自己权限对应的功能,管理员仅能进行系统用户和学院部门的管理,院领导仅能进行院领导的审批功能,拟稿人可以进行公文管理,各个部门用户可以进行公文的审批和查看可下发的公文。head.jsp是顶上显示具体用户信息和提供修改密码跳转的界面。

对各个功能的访问控制如下:

相对应的角色type:

4.systemuser.jsp

systemuser.jsp对应着管理员身份才能访问的系统用户管理界面。在这里,管理员可以直接管理系统用户,也可以对注册的用户进行审核,审核通过后用户即可正常登录。

5.systemuser_add.jsp

systemuser_add.jsp就是相应的添加系统用户的界面。

6.dep.jsp

dep.jsp对应着管理员身份才能访问的学院部门管理界面。在这里,管理员可以直接管理学院的部门。

7.dep_add.jsp

dep_add.jsp就是相应的添加学院部门的界面。

8.document.jsp

document.jsp对应着拟稿人身份才能访问的公文管理管理界面。在该界面,拟稿人可以添加新的审批公文,并查看其他公文的状态。如公文审批未通过,需要删除后重新添加。

9.document_add.jsp

document_add.jsp就是相应的添加新的审批公文的界面。需要注意的是,一个公文写好后,需要指定该公文的审批部门和下发部门,只有当审批部门和院领导审批通过后,下发部门才会收到该公文。

10.audit1.jsp

audit1.jsp对应着部门成员身份才能访问的公文审批界面。在这里部门成员可以审批公文。

11.xiafa.jsp

xiafa.jsp对应着部门成员身份才能访问的可下发公文界面。在这里部门成员可以查看可以下发的公文。

12.document_show.jsp

document_show.jsp对应着部门成员身份才能访问的可下发公文界面。在这里部门成员可以查看可以下发的公文的具体内容。

13.password.jsp

password.jsp就是修改密码的界面。

14.audit.jsp

audit.jsp是院领导审批的界面,院领导可以在此对公文进行审批。

二、系统底层架构

1.访问控制

在后端设计中,我们经常会遇到账号密码不能为空、账号已存在的情况。为此,我们需要进行一定的控制措施。我们将这个措施封装到了admin.js中:

点击查看admin.js代码
//用户登录,js事件处理
//jQuery动态点击事件绑定
function login(path, closed) {
	 
	//#saveBtn绑定的是提交按钮
	//on表示将事件绑定在body上,第一个参数click表示点击事件绑定到body对象,第二个表示冒泡到id=saveBtn则触发,第三个是触发的函数
	$('body').on('click', "#saveBtn", function() {
		var name = $("#name").val();// $("#name").val()是获取id为name绑定的值
		var pwd = $("#pwd").val();
		if (name == "" || pwd == "") {
			alert("账号密码不能为空");
			return false;
		}
		//jQuery AJAX 方法是一种与服务器交换数据的技术,可以在不重新载入整个页面的情况下更新网页的一部分。
		//语法:$.ajax({name:value, name:value, ... })
		$.ajax({
			type : 'POST',	//type 	规定请求的类型(GET 或 POST)。
			//path =  /gwlzxt/admin/login.jsp
			url : path + '/AdminLoginServlet?name=' + name + "&pwd=" + pwd,//url 	规定发送请求的 URL。默认是当前页面。
			success : function(data) {//success(result,status,xhr) 	当请求成功时运行的函数。
				if (data == "1") {
					alert('用户名或密码错误或是未审核');
				} else {
					location.href = path+'/admin/index.jsp';
				}
			},
			error : function(res) {//error(xhr,status,error) 	如果请求失败要运行的函数。

			},
		});

	});
	

	$('body').on('click', "#resetBtn", function() {
		 $("#name").val("");
		 $("#pwd").val("");
	});
}
// 修改密码
function editpass(path) {
	 
		$('#showModal').modal({
			remote : path + '/admin/password.jsp',
			backdrop : 'static', // 点击空白不关闭
			keyboard : false, 
		});
 
	$("#showModal").on("hidden.bs.modal", function() {

		// 这个#showModal是模态框的id

		$(this).removeData("bs.modal");

		$(this).find(".modal-content").children().remove();

	});

	$('body').on('click', "#saveBtn1", function() {
		var newpwd = $("#newpwd").val();
		var repeatpwd = $("#repeatpwd").val();
		if (newpwd == "" || repeatpwd == "") {
			alert("密码不能为空");
			return false;
		}
		
		if(newpwd!=repeatpwd){
			
			alert("两次密码不一致");
			return false;
		}

		$.ajax({
			type : 'POST',
			url : path + '/PwdUpdateServlet?newpwd=' + newpwd + "&repeatpwd=" + repeatpwd,
			success : function(data) {
			 
					alert('修改成功');
					location.reload();
				 
			},
			error : function(res) {

			},
		});

	});
	

	$('body').on('click', "#resetBtn1", function() {
		 $("#newpwd").val("");
		 $("#repeatpwd").val("");
	});
	
	
}
// 添加管理员
function adminAdd(path) {
	$("body").append(
			"<div id='dlg_systemuser_add' style='padding:20px;'></div>");
	$('#dlg_systemuser_add')
			.dialog(
					{
						href : path + '/admin/systemuser_add.jsp',
						modal : true,
						closed : false,
						title : '添加系统用户',
						width : 400,
						height : 300,
						buttons : [
								{
									text : '提交',
									iconCls : 'icon-ok',
									handler : function() {
										$('#form_systemuser_add')
												.form(
														'submit',
														{
															url : path
																	+ '/AdminAddServlet',
															onSubmit : function() {
																return $(this)
																		.form(
																				'validate');
															},
															success : function(
																	data) {
																if (data == "-1") {
																	$.messager
																			.alert(
																					'系统消息',
																					'用户名已存在',
																					'error');
																} else {
																	$.messager
																			.alert(
																					'系统消息',
																					'添加成功',
																					'info',
																					function() {
																						$(
																								'#dlg_login')
																								.dialog(
																										'refresh');
																						$(
																								'#dlg_login')
																								.dialog(
																										'close');
																						location.href = path
																								+ '/admin/systemuser.jsp';
																					},
																					false);
																}
															}
														});
									}
								},
								{
									text : '重置',
									iconCls : 'icon-reload',
									handler : function() {
										$('#dlg_systemuser_add').dialog(
												'refresh');
									}
								} ]
					});
}
// 用户注销
function logout(path) {
	$.ajax({
		type : 'POST',
		url : path + '/RemoveServlet',
		data : 'mark=admin',
		success : function(msg) {
			window.location.href = path + '/admin/login.jsp';
		}	});
}
// 解析JSON
function parseJson(text) {
	// extract JSON string
	var match;
	if ((match = /\{[\s\S]*\}|\[[\s\S]*\]/.exec(text))) {
		text = match[0];
	}
	var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
	cx.lastIndex = 0;
	if (cx.test(text)) {
		text = text.replace(cx, function(a) {
			return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
		});
	}
	if (/^[\],:{}\s]*$/.test(text.replace(
			/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(
			/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
			']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
		return eval('(' + text + ')');
	}
	throw 'JSON parse error';
}
// 上传文件
function upload(path) {
	$("body").append("<div id='dlg_upload' style='padding:20px;'></div>");
	$('#dlg_upload')
			.dialog(
					{
						href : path + '/admin/upload_file.jsp',
						modal : true,
						closed : false,
						title : '上传文件',
						width : 450,
						height : 150,
						closable : true,
						buttons : [
								{
									text : '上传',
									iconCls : 'icon-ok',
									handler : function() {
										$('#upload_file')
												.form(
														'submit',
														{
															url : path
																	+ '/admin/upload_json.jsp',
															onSubmit : function() {
																return $(this)
																		.form(
																				'validate');
															},
															success : function(
																	data) {
																var json = parseJson(data);
																if (json.error === 1) {
																	$.messager
																			.alert(
																					'系统消息',
																					json.message,
																					'error');
																} else {
																	// window.navigate(path+'/index.jsp');
																	$.messager
																			.alert(
																					'系统消息',
																					'上传成功',
																					'info',
																					function() {
																						$(
																								'#dlg_upload')
																								.dialog(
																										'refresh');
																						$(
																								'#dlg_upload')
																								.dialog(
																										'close');
																						$(
																								'#paths')
																								.val(
																										json.url);
																					},
																					false);
																}
															}
														});
									}
								}, {
									text : '重置',
									iconCls : 'icon-reload',
									handler : function() {
										$('#dlg_upload').dialog('refresh');
									}
								} ]
					});
}

2.数据库操作相关方法

首先在SqlHelper中,我们封装了若干种方法,每一个方法都能返回数据库中某个表的所有值。因此我们如果想要进行库表操作时,使用该类内数据库表相对应的方法即可生成对应sql语句:

在DBHelper中,封装了执行sql查询语句后获取返回的结果集的方法,如果想要获取sql语句执行后返回的结果集,使用该类内相对应的方法即可。

在CRUDHelper中,封装了执行sql语句后获取返回值的方法,如果想要获取sql语句执行后返回的结果集,使用该类内相对应的方法即可。

需要注意的是,executeQuery() 用于执行查询语句,并返回一个 ResultSet 对象,可以通过这个对象来处理查询结果集。executeUpdate() 用于执行 INSERT、UPDATE、DELETE 等操作,返回一个整数值,表示受影响的行数。如果需要获取结果集,可以使用 ResultSet 对象处理。将数据从 ResultSet 中提取出来,并进行相应的处理和操作。

在SQLConnection中,定义了数据库的驱动和连接方法,通过该方法我们可以成功的连接到数据库:

3.功能操作相关方法

CheckerController类封装了部门审批方法,部门在审批公文时调用该方法即可。

DeleteController类封装了删除方法,管理员用户的学院部门管理的删除模块、管理员用户的系统用户管理的删除模块、拟稿人用户的公文管理的删除模块调用该方法即可。

DepartmentController类封装了添加部门方法,管理员添加部门时调用该方法即可。

FileController类封装了添加公文方法和更新检查表方法,拟稿人在添加公文时调用该方法即可。

InsertAdminController类封装了添加用户方法,需要添加用户时直接调用该方法即可

LeaderController类封装了院领导审批方法,需要院领导审批时直接调用该方法即可。

LoginController类封装了用户登录方法,用户登录时直接调用该方法即可。

PasswordController类封装了更新密码方法,更新密码时直接调用该方法即可。

RemoveController类封装了退出方法,退出时直接调用该方法即可。

UpdateController类封装了更新用户状态方法,更新用户状态方法时直接调用该方法即可。

3.安全性措施

  • 加密算法的选择

为保证密码方案的安全性,应该使用符合国家密码管理局规定的加密算法。参考了《GMT 0007 2012 电子政务电子认证服务应用指南》、GMT 0054-2018 《信息系统密码应用基本要求》和国家标准GB/T 39786-2021《信息安全技术 信息系统密码应用基本要求》等相关标准,我们采用SM3和SM4进行数据加密。

在InsertAdminController类中,我们增加角色时需要将口令进行加密处理。由于密码长度通常不会很长,因此我们采用了SM3算法,对用户输入的口令进行哈希运算并存入数据库中。

在FileController类中,我们新建公文时需要将公文进行加密处理。由于公文长度通常不会很长,因此我们采用了SM4算法,对用户输入的口令进行加密并存入数据库中。

  • 密码长度和复杂度

为防止破解,密码的长度和复杂度至关重要。密码长度越长、复杂度越高,则被破解的难度就越大,安全性也就越高。因此,建议设置较长、包括大小写字母、数字和特殊符号的复杂密码,并采取强制修改密码策略和不同用户不同密码的策略。

SM3 算法是国家密码管理局发布的一种哈希算法,其输出固定为 256 位(32 字节),长度固定,安全性高。在SM4加密过程中,使用了一个长度为 16 字节(128 位)的密钥。密钥的长度对 SM4 算法的安全性有直接影响。一般而言,密钥长度越长,破解难度越大,但同时也会带来更高的计算和存储成本。因此,在实际应用中,需要根据具体场景进行权衡和选择。

  • 密码存储和传输

为了保证密码的安全性,应该采用不可逆加密的方式存储密码。同时,在密码传输过程中,也需要采用加密协议,我们使用GMSSL安全传输协议对传输进行保护。

三、实验感想

经过本次实验,我基本熟悉了web开发的流程,可以和团队一起开发web项目,基本上实现了数据的安全传输,可以通过国密算法保护用户数据的完整性、机密性、不可否认性,通过GMSSL保护传输过程,可以开发一个产品使其基本上又好用、又安全,了解了配置服务器的方法,申请域名的方法、申请国密SSL证书的方法。

posted @ 2023-06-03 20:53  acacacac  阅读(119)  评论(0编辑  收藏  举报