본문 바로가기
Spring/ICS단계적보안성평가 프로젝트(한이음)

[Spring] ICS단계적보안성평가WEB - DA 단계적 보안성 평가 코드

by 태옹 2021. 8. 5.

Non Direct/Direct DA 단계적 보안성 평가 조건

1) DA 단계적 보안성 평가 관리(EP DA 중요도 평가)

- (영향성 분석 = Emergency Preparedness Function) AND

- (대체 수단 존재 여부 = Y) AND (손상여부 탐지방법 존재 여부 = Y) AND (교육 훈련 계획 존재 여부 = Y)

 

2) DA 단계적 보안성 평가 관리(BOP DA 중요도 평가)

- (영향성 분석 = Important to Safety) AND

- (안전 시스템에 악영향 여부 = N) AND (발전정지 유발 여부 = Y) AND (발전소 상태 정보 제공 여부 = Y) AND (심층 방호 관련 여부 = N)

 

3) DA 단계적 보안성 평가 관리(Indirect DA 중요도 평가)

- (안전/보안 관련 지시/경보 기능 수행 여부 = N) OR

- (안전/보안 관련 지시/경보 기능 대체 수단 존재 여부 = Y) AND (손상여부 탐지방법 존재 여부 = Y) AND (손상탐지 시간 내 평가 기준 존재 여부= Y) AND (교육 훈련 계획 존재 여부= Y)

 


평가 프로세스

 

1. 평가할 자산 선택 (이미 평가가 완료된 자산은 재평가할 수 없음) 

2. 단계적 보안성 평가 진행 (자산의 '영향성 분석' 유형에 따라 평가 시작 지점이 다름)

위의 평가 조건에 맞게 절차를 구성하면 다음과 같은 평가가 나온다.

 


프로세스에 관련된 테이블 ERD

1. 자산 식별 상세유형이 NULL인 자산을 리스트업

2. 자산 선택 후 평가가 완료되면 master테이블인 '단계적 보안성 평가 관리'테이블(실제 DB에는 'SecurityAssessment'로 설정)에 자산번호와 결정된 자산식별유형이 저장됨. 이때 pk인 보안성 평가 코드는 auto increment로 지정되어 있음.

3. 마스터(SecurityAssessment) 테이블에 auto로 생성된 보안성 평가 코드를 getter로 불러와서 EP, BOP, Indirect의 pk값으로 set해줌. 나머지 칼럼 정보들과 함께 각각의 테이블에 저장함.

4. DA테이블에는 평가된 유형으로 업데이트

 

 


작성 코드 (back)

1. VO, DTO

더보기

1-1. SecurityAssessmentVO

@Data
public class SecurityAssessmentVO {
	private Long SA_no;
	private String SA_daID;
	private Date SA_date;
	private String SA_IdentifyType;
}

 

1-2. SecurityAssessDTO

@Data
public class SecurityAssessDTO {
	private Long SA_no;
	private String daname;
	private String SA_daID;
	private String daptype;
	private String daPDetailType;
	private Date SA_date;
	private String SA_IdentifyType;
}

 

1-3. EPVO

@Data
public class EPVO {
	private Long epNo;
	private String epAlterContent;
	private String epAlterTypeComment;
	private String epAlterDoc;
	private String epDmgDetMContent;
	private String epDmgDoc;
	private String epETContent;
	private String epETDoc;
}

 

1-4. BOPVO

@Data
public class BOPVO {
	private Long bopNo;
	private String bopAdverseEffectsContent;
	private String bopPowergenStop;
	private String bopPlantStatusInfo;
	private String bopDeepProtectiContent;
}

 

1-5. IndirectVO

@Data
public class IndirectVO {
	private Long indirectNo;
	private String indIWPerformContent;
	private String indIWAlterContent;
	private String indDmgDetectContent;
	private String indDmgDetectDoc;
	private String indDmgDetectASContent;
	private String indDmgDetectASDoc;
	private String indETContent;
	private String indETDoc;
}

 

2. Mapper(Repository)

SecurityAssessmentMapper.xml만 첨부

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hanium.mapper.SecurityAssessmentMapper">
	<select id="getList"
		resultType="com.hanium.domain.SecurityAssessDTO">
		SELECT *
		FROM (SELECT max(SA_no) as SA_no,
		SA_daID,SA_date,SA_IdentifyType
		FROM SecurityAssessment WHERE
		SA_IdentifyType!=''
		GROUP BY SA_daID) as sa, DA
		WHERE SA_daID=DA.daid;
	</select>
	<select id="read"
		resultType="com.hanium.domain.SecurityAssessmentVO">
		select * from SecurityAssessment where SA_no =
		#{SA_no}
	</select>
	<select id="getSA_no"
		resultType="com.hanium.domain.SecurityAssessmentVO">
		SELECT SA_no FROM SecurityAssessment where SA_daID=#{SA_daID};
	</select>
	<select id="identifyType_is_null"
		resultType="com.hanium.domain.DAVO">
		SELECT * FROM DA WHERE daIdentifyType IS NULL;
	</select>
	<insert id="insert" useGeneratedKeys="true" keyProperty="SA_no">
		insert
		into SecurityAssessment
		(SA_daID,SA_IdentifyType)
		values
		(#{SA_daID},#{SA_IdentifyType})
	</insert>
	<update id="update">
		update SecurityAssessment
		set SA_daID=#{SA_daID},
		SA_IdentifyType=#{SA_IdentifyType}
		where SA_no=#{SA_no}
	</update>
</mapper>

 

3. Service ⭐핵심코드

평가 절차는 하나의 트랜잭션으로 처리한다. (@Transactional사용)

EP, BOP, Indirect는 조건만 다르고 데이터를 처리하는 코드는 동일한 알고리즘으로 진행되기 때문에 registerEP만 첨부하였음!

SecurityAssessmentServiceImpl.java 코드의 일부만 첨부

@Log4j
@Service
@AllArgsConstructor
public class SecurityAssessmentServiceImpl implements SecurityAssessmentService {
	private SecurityAssessmentMapper mapper;
	private DAMapper mapper_DA;
	private EPMapper mapper_ep;
	private BOPMapper mapper_bop;
	private IndirectMapper mapper_ind;

	@Transactional
	@Override
	public boolean registerEP(SecurityAssessmentVO sa, EPVO ep) {
		log.info("[CONTROLLER]register : " + sa);
		// 1. 마스터 테이블인 SecurityAssessment에 먼저 기본 정보 저장 (자산번호, 유형)
		mapper.insert(sa);

		// 2. EP테이블에 정보 저장
		SecurityAssessmentVO temp = mapper.getSA_no(sa.getSA_daID());
		// 마스터테이블에 저장될 때 자동생성된 pk값을 조회(ep테이블의 pk와 동일)
		log.info("[CONTROLLER]temp : " + temp.getSA_no());
		ep.setEpNo(temp.getSA_no()); // EpNo만 아직 지정되지 않은 상태이기 때문에 받아온 pk값을 setter로 저장
		mapper_ep.insert(ep);

		//3. DA테이블에 자산 식별 상세유형 업데이트
		mapper_DA.updateIdentifyType(sa.getSA_IdentifyType(), sa.getSA_daID().toString());
		return true;
	}
    ...
}

 

4. Controller

SecurityAssessmentController만 첨부

@Controller
@Log4j
@RequestMapping("/SecurityAssessment/*")
@AllArgsConstructor
public class SecurityAssessmentController {
	private SecurityAssessmentService service;
	private EPService service2;
	private BOPService service3;
	private IndirectService service4;
	private DAService service5;

	/* EP */
	@GetMapping({ "/assessEP", "/assessBOP", "/assessIndirect" })
	public void startAccess(@RequestParam("daid") String daid, Model model) {
		model.addAttribute("daid", daid);
	}

	// 글을 등록하는 경우에는 get방식이 아니라 post방식을 사용한다.
	@PostMapping("/registerEP")
	public String registerEP(SecurityAssessmentVO sa, EPVO ep) {
		if (service.registerEP(sa, ep))
			log.info("register success");
		return "redirect:/SecurityAssessment/list";
	}
    ...
}

 


작성 코드 (front)

프론트 단에서는 대부분 자바스크립트로 EP, BOP, Indirect DA의 조건을 판별하는 코드이다.

 

1. 자산 선택 모달 html코드

<!-- Modal -->
<div class="modal fade" id="staticBackdrop" data-backdrop="static"
	data-keyboard="false" tabindex="-1"
	aria-labelledby="staticBackdropLabel" aria-hidden="true">
	<div class="modal-dialog modal-lg modal-dialog-centered">
		<div class="modal-content">
			<div class="modal-header">
				<h5 class="modal-title" id="staticBackdropLabel">DA 단계적 보안성 평가
					시작하기</h5>
				<button type="button" class="close" data-dismiss="modal"
					aria-label="Close">
					<span aria-hidden="true">&times;</span>
				</button>
			</div>
			<div class="modal-body">
				<div class="h5box">
					<h6>
						<b>단계적 보안성 평가를 진행할 DA를 선택해주세요.</b>
					</h6>
				</div>
				<br>
				<form class="center_form">
					<div style="float: right;">
						<select name="search" id="">
							<option class="dropdown-item" value="DAName">자산명</option>
							<option class="dropdown-item" value="DAId">자산번호</option>
							<option class="dropdown-item" value="daImpact">영향성분석</option>
						</select> <input type="search" name="" value="" placeholder="자산명 입력">
						<button type="button" name="button"
							class="btn btn-outline-secondary">검색</button>
					</div>
				</form>
				<br> <br>
				<table class="table table-hover">
					<thead>
						<tr>
							<th scope="col" style="width: 30px;">Id</th>
							<th scope="col">자산번호</th>
							<th scope="col">자산명</th>
							<th scope="col">영향성분석</th>

						</tr>
					</thead>
					<tbody id="selectDA_modal">
						<c:forEach items="${undecide}" var="da" varStatus="status">
							<tr class="modal_items"
								onclick="select(<c:out
								value="${status.index}" />, '<c:out value="${da.daid}" />', '<c:out value="${da.daImpact}" />')">
								<td scope="row" style="width: 30px;"><c:out
										value="${status.count}" /></td>
								<td><c:out value="${da.daid}" /></td>
								<td><c:out value="${da.daname}" /></td>
								<td><c:out value="${da.daImpact}" /></td>

								<td></td>
							</tr>
						</c:forEach>
					</tbody>
				</table>
			</div>


			<div class="modal-footer">
				<br> <b><span style="color: #dc3545;" id="select_da">평가할
						자산을 선택해주세요.</span></b>
				<button type="button" class="btn btn-secondary" data-dismiss="modal">취소</button>
				<button type="button" class="btn btn-danger" id="start"
					onclick="assessStart()" disabled="disabled">평가시작</button>
			</div>
		</div>
	</div>
</div>

 

1-2. 모달 javascript

var daId;
var flag=0;	//평가 루트 1:ep부터, 2:bop부터, 3:indirect부터 

function select(val, daname, daImpact){
	var target = document.getElementsByClassName("modal_items");
	daId=daname;
	
	if(daImpact=="Emergency Preparedness Function"){
		flag = 1;
	}else if(daImpact=="Important to Safety"){
		flag = 2;
	}else{
		flag = 3;
	}
	target[val].style.backgroundColor = "rgb(146 171 198 / 25%)";
	 $( '#select_da' ).text( daname+"자산을 평가합니다." );
	 $("#start").attr("disabled", false);
	for(var i=0 ;i<target.length ; i++ ){
		if(i!=val)
			target[i].style.backgroundColor = "transparent";
	}
}

function assessStart(){
	document.getElementById("notifyType").innerHTML = daId+"의 단계적 보안성 평가를 시작합니다.";
	$(".notify").toggleClass("active");
	  $("#notifyType").toggleClass("success");

	  setTimeout(function(){
	    $(".notify").removeClass("active");
	    $("#notifyType").removeClass("success");
	  },1600);
	  
	  
	  if(flag==1){
		  setTimeout(function(){location.href = "/SecurityAssessment/assessEP?daid="+daId;},1800);
		}else if(flag==2){
			setTimeout(function(){location.href = "/SecurityAssessment/assessBOP?daid="+daId;},1800);
		}else{
			setTimeout(function(){location.href = "/SecurityAssessment/assessIndirect?daid="+daId;},1800);
		}

}

 

 

2. EP Process Javascript

- (영향성 분석 = Emergency Preparedness Function) AND

- (대체 수단 존재 여부 = Y) AND (손상여부 탐지방법 존재 여부 = Y) AND (교육 훈련 계획 존재 여부 = Y)

/*ep판별*/
var flag = 1; //판별 신호 (1=ep, 0=indirect검사)

function assess_btn() {
	var daid = $('#daid').val();
	console.log(daid);
	
	flag = 1;
	var radios = $(":radio[value='Y']");
	for (var i = 0; i < radios.length; i++) {
		var $this = $(radios[i]);

		// (영향성 분석 = Emergency Preparedness Function) AND
		if (!$this.is(":checked"))
			flag = 0;

	}

	if (flag == 0) {
		$("#ep_no").show();
		$("#ep_yes").hide();
		//location.href="./SA_BOP.html"

	} else if (flag == 1) {
		$("#ep_yes").show();
		$("#ep_no").hide();
		//$("modal_ok").on("click",function() {location.href="./SA_list.html"});
	}

	$("#modal_ok").on("click",function() {
		if (flag == 0) {
			location.href = "/SecurityAssessment/assessIndirect?daid="+ daid;
			return false;
		} else if (flag == 1) {
			document.getElementById('form').submit();
			return true;
		}
	});
}

 

 

3. BOP Process Javascript

- (영향성 분석 = Important to Safety) AND

- (안전 시스템에 악영향 여부 = N) AND (발전정지 유발 여부 = Y) AND (발전소 상태 정보 제공 여부 = Y) AND (심층 방호 관련 여부 = N)

/*bop판별*/
var cnt = 0; //판별 신호 (cnt=4 bop)

function assess_btn() {
	var daid = $('#daid').val();
	console.log(daid);
	
	cnt = 0;
	var radios = $(":radio[value='Y']");
	for (var i = 0; i < radios.length; i++) {
		var $this = $(radios[i]);
		console.log($this.is(":checked"));
		// (영향성 분석 = Important to Safety) AND
		// (안전 시스템에 악영향 여부 = N) AND (심층 방호 관련 여부 = N)
		if ((i == 0 || i == 3) && !$this.is(":checked"))
			cnt++;
		//(발전정지 유발 여부 = Y) AND (발전소 상태 정보 제공 여부 = Y)
		if ((i == 1 || i == 2) && $this.is(":checked"))
			cnt++;
	}
	console.log(cnt);

	if (cnt == 4) {
		$("#bop_yes").show();
		$("#bop_no").hide();

	} else {
		$("#bop_no").show();
		$("#bop_yes").hide();
	}

	$("#modal_ok").on("click", function() {
		console.log(cnt);
		if (cnt == 4) {
			document.getElementById('form').submit();
			return true;
		} else {
			location.href = "/SecurityAssessment/assessIndirect?daid="+ daid;
			return false;
		}
	});
}

 

 

4. Indirect Process Javascript

- (안전/보안 관련 지시/경보 기능 수행 여부 = NOR

- (안전/보안 관련 지시/경보 기능 대체 수단 존재 여부 = Y) AND (손상여부 탐지방법 존재 여부 = Y) AND (손상탐지 시간 내 평가 기준 존재 여부= Y) AND (교육 훈련 계획 존재 여부= Y)

/*indirect판별*/

//판별 신호 flag1과 flag2를 모두 고려
var flag1 = 0;	// 안전/보안 관련 지시/경보 기능 수행 여부 고려 flag
var flag2 = 1;	// 그 외 조건 고려 flag

function assess_btn(){
	var daid = $('#daid').val();
	console.log(daid);
	
	flag1 = 0;
	flag2 = 1;
	
	/*(안전/보안 관련 지시/경보 기능 수행 여부 = N)*/
	const group1NodeList
	  = document.getElementsByName('group1');
	  
	group1NodeList.forEach((node) => {
	    if(node.checked)  {
	    	if(node.value=='No')
	     flag1=1;	//무조건 indirect
	    }
	  }) 
	  
	var radios = $(":radio[value='Y']");
	for (var i = 0; i < radios.length; i++) {
		var $this = $(radios[i]);

		if (!$this.is(":checked"))
			flag2 = 0;	//무조건 direct
	}

	if (flag1 == 1) {
		$("#indirect_msg").text("해당 자산은 Indirect DA입니다.");
	} else if (flag1 != 1 && flag2 == 0) {
		$("#indirect_msg").text("해당 자산은 Direct DA입니다.");
	}else{
		$("#indirect_msg").text("해당 자산은 Indirect DA입니다.");
	}
	
	$("#modal_ok").on("click", function() {
		if (flag1 == 1) {
			document.getElementById('form').submit();
		} else if (flag1 != 1 && flag2 == 0) {
			location.href = "/SecurityAssessment/registerDirect?daid="+daid;
		}else{
			document.getElementById('form').submit();
		}
	});
}

 

Indirect DA가 아니면 Direct DA로 분류되지만 우리 프로젝트에서는 Direct DA부분은 다루지 않기 때문에 코드는 따로 첨부하지 않겠다. 따로 Direct DA를 저장하는 테이블은 없지만 마스터테이블과 DA테이블에만 Direct DA로 분류된다는 것을 명시해준다. (direct테이블이 따로 없다는 것만 제외하면 ep프로세스와 거의 동일하다.)

 

 

Indirect DA자산 평가 시뮬레이션

 

음 마지막에 디테일 페이지는 다시 손 좀 봐야겠다..🤦‍♀️

댓글