1. 기본적인 SecureString 사용법

https://stackoverflow.com/questions/37662937/storing-credentials-to-run-powershell-script-in-php-application-remotely

 

Storing credentials to run PowerShell script in PHP application (remotely)

I'm running a Windows 2012 R2 server with XAMPP (php/mysql/apache) and PowerShell v3. For the past couple of months, my code has been working just fine to store and retrieve an encrypted password ...

stackoverflow.com

 

2. SecureString을 PHP에 올렸다가 실패한 어느 뉴비의 자문자답

https://stackoverflow.com/questions/51365603/using-exec-to-run-powershell-script-hangs-if-i-try-to-set-credentials

 

Using exec to run PowerShell script hangs if I try to set credentials

Firstly I apologise but I am pretty new to PHP and PowerShell, we all have to start somewhere! I am creating a utility where everyday IT tasks can be performed from a central web based console. I...

stackoverflow.com

 

3. 우리는 해냈다 늘 그랬듯이

stackoverflow.com/questions/23699500/convertto-securestring-gives-different-experience-on-different-servers/23700513

 

ConvertTo-SecureString gives different experience on different servers

I am running into an issue creating a Credential Object from an XML File on a remote server. Here is the code I am using to test XML File stackoverflow.com

 

 

먼저, 이것을 하려는 목적은

1. 파워쉘기반 운영서버에 (감히) WEBWAS를 돌릴 수 없다.

2. 따라서 운영서버 옆에 나만의 WEBWAS를(다른 운영중인 윈도우서버안에) 구축하여, Remote Powershell로 제어를 하고 싶었다.

3. 웹서버는 IIS를 사용하고, PHP는 FastCGI로 구성했다.(feat 구글링)

4. 간단한 원리는 PHP가 되는 서버에서 Remote Powershell로 운영서버에 Powershell을 날려서 데이터를 가져오고 그것을 Web으로 쏘는 것이다. 그러려면 exec_shell 메서드가 필요하다.

[트러블슈팅1] PHP의 exec_shell 메서드를 사용하여 서버 자원에 접근하려면 PHP가 설치된 서버의 cmd.exe에 IIS_IUSRS에 Read 및 Execute 권한이 필요하다. (Users의 권한을 보안상 제어하는 경우)

5. 리모트 파워쉘을 다른 클라이언트에서 접근하려면 수동으로 패스워드를 입력해서 사용한다. 하지만 자동화를 위해서는 반드시 서버의 인증 정보를 가지고 있다가 원격 접속시 사용해야 한다.

6. 그래서 사용하는 방법이 인증 정보를 만들어 명령을 전달하는 방법이다. 서버의 $id와 (반드시 SecureString으로 변환된) $passwd를 가지고 인증정보($cred)를 만든 후(PSCredential), 그 인증정보를 가지고 $session정보를 만들면 된다.(New-PSSession) 그리고 마지막으로 Invoke-Command를 통해 파워쉘 명령을 Target Server에 날린다.

정리하면

1. $passwd를 SecureString으로 변환한다.
2. $credential = New-Object PSCredential $id, $passwd (SecureString형태)
3. $Session = New-PSSession -computername $TargetServer -credential $credential
4. Invoke-Command -session $session -filepath "실행하려는파워쉘.ps1" -argumentlist "인자값"
  ※ 필요한 데이터 $id, $passwd, $TargetServer, 실행하려는파워쉘 및 인자값

 

[트러블슈팅2] PHP의 exec_shell이 SecureString 처리를 못함

$password를 SecureString으로 변환하는 방법은 두 가지가 있다.

1. 서버에 저장된 평문패스워드를 불러온 후(Get-Content)
2. $passwd = ConvertTo-SecureString -AsPlainText -Force -String $plainPW(평문패스워드)
1. 서버에 저장된 암호화된 패스워드를 불러온다. (이는 ConvertFrom-SecureString을 거친 후 서버에 난수로 저장됨)
2. $passwd = ConvertTo-SecureString -String $encryptedPW (암호회된 패스워드)

 

그런데 운영자 관점에서 패스워드 유출이 꺼려지니 당연히 암호화된 패스워드를 사용하는 두 번째 방법을 활용하게 된다. 그런데! PHP서버 내부의 cmd에서 돌리면 너무나 잘돌아가던 파워쉘이 exec_shell에만 들어가면...실행을 못한다.

편의상 $pass를 평문암호, $passwd를 SecureString으로 encrypted된 암호라고 하면, 아래의 두 경우 모두 cmd에서는 결과값을 가져오는데, php에서는 결과값을 가져오지 못한다.

$pass = ConvertFrom-SecureString -SecureString $passwd
echo $pass #실패
$passwd = ConvertTo-SecureString -String $encryptedPW
echo $passwd #실패

그래서 그 이후의 $credential을 못 만들어서 php 자체를 못 쓰게 된다는 것.

이러한 문제 때문에 나는 계속 첫번째 방법인 평문패스워드를 -AsPlainText로 사용하였으나 이는 커다란 보안 취약점이다. 그래서 찾아보던 중 오아시스같은 3번째 링크에 다음의 설명을 발견했다.

When you use the command ConvertTo-SecureString it encrypts the plaintext password with the encryption key on the local machine, under your user account

즉, 내가 이해하기로는 SecureString을 만들때 반드시 key값이 필요한데, key값을 별도로 명시하지 않으면, local machine에 있는 user account를 key값으로 쓴다는 것이고, cmd로는 잘 돌던게 php에서는 안 돌아가는 이유는! php가 shell_exec 메서드로 수행하는 user계정이, cmd에서 만든 ConvertFrom-SecureString를 제대로 처리할리가 없던 것이었다.

그래서 key를 별도로 쓰면 해결되는 문제였다. 다음과 같이 해결하였다.

<인코딩><패스워드를 난수화하여 서버에 저장>
$key = (3,4,2,3,56,34,254,222,1,1,2,23,42,54,33,233,1,34,2,7,6,5,35,43)
$plainPassword = "평문패스워드"
$securePassword = $plainPassword | ConvertTo-SecureString -AsPlainText -Force  #암호화된 패스워드
$securePasswordKey = ConvertFrom-SecureString $securePassword -key $key   #암호화된 패스워드를 key로 난수화
Set-Content -Path "c:\패스워드.txt" -Value $securePasswordKey 
<디코딩><난수화된 패스워드를 불러와서 사용>
$key = (3,4,2,3,56,34,254,222,1,1,2,23,42,54,33,233,1,34,2,7,6,5,35,43)
$pass = Get-Content -Path "c:\패스워드.txt"
$passwd = ConvertTo-SecureString -String $pass -Key $key

이후 $cred, $session 잘 만들어진다.

드디어 3개월에 걸친 나의 고민을 타파해서

블로그에 글을 안 남길 수 없다.

카카오톡뿐 아니라 그동안 개행문자때문에 데이터 가공에 고생했던 나날들이 떠오른다.

얼마나 미개하게 했었는지 서술한다. 카카오톡 대화를 내보내기 하여 KakaoTalkChats.txt을 보면

2019년 7월 2일 오전 7:52, 아이디 : 네~ 감사합니다~^^

그리고 항상 잘 읽고 있습니다

 

엔터키가 눌려진 대화를 저장하기 위해 배치 스크립트를 돌리려면

이거 처리하기가 너무 골치가 아픈거라...

방법1) 배치파일로 문서 파싱하는 툴을 써서(필자의 경우는 오토핫키)

임시 변수에 현재 행의 데이터 중 시간과 아이디를 임시 저장한다.

그리고 다음 행의 데이터를 읽을 때, 아이디의 특수한 값이 감지되지 않으면

'이전 날짜값저장변수+데이터'를 새로운 텍스트에 저장한다.

그러면 가공된 데이터는 아래와 같이 변경된다.

2019년 7월 2일 오전 7:52, 아이디 : 네~ 감사합니다~^^

2019년 7월 2일 오전 7:52, 아이디 : 그리고 항상 잘 읽고 있습니다

 

이런 미개한 방법으로 수백~천라인의 데이터가 리패키징 되는 과정을 처리하며 PC자원과 시간의 낭비를 했다.

이과정은 DB에 입력할 라인을 무수히 증가시켰지만,

일단 변환된 텍스트를 db에 밀어넣는건 개꿀이다. (하지만 DB에 밀어넣을때도 년,월,일,ID,내용 파싱하고 insert할 값으로 변환하는데 PC자원을 사용하므로 이중 자원의 소비를 했다)

이 방법의 가장 큰 장점은 PHP로 Web에 출력할 때, 뉴라인을 고려하지 않아도 된다.

<td>테그를 써서 라인이 구별되는 편리함 때문에 이 방법을 고수해왔다.

(사실 더 미개한 이야기지만 매일의 대화를 저장한 것을 날짜.html 파일로 만들어 보관하고 있었다.

데이터 서칭은 포기한 셈. 그러다가 추후 피땀흘려 mysql과 php연동을 웹상에서 하게 되었다.)

 

매일 카톡을 실행하고 대화내용 내보내기를 해서 DB에 넣는 노가다 뛰는것도 힘들었지만, 카카오톡 유저들이 말하고 삭제하면 삭제된 메시지로 기록된다. 이에 노이로제가 걸려 다음의 방법을 생각하게 된다. 그런데 이 마저도 KaKaoTalkChats.txt 를 별도로 불러와서 '삭제된 메시지'를 손으로 끼워맞추며 천문학적인 시간을 데이터 복원 작업에 쓰는 미개함을 보여주었다. 그러다가 문득 든 생각.

방법2) 카톡봇을 이용해서 데이터를 만든다.

아예 DB에 밀어넣기 쉬운 방법으로 '날짜','ID','내용'으로 저장하겠다.

그 결과는 다음과 같다. 그러나!!!!!

'2019-08-05 08:42:53', '아이디', '오늘도 즐거운 하루되세요~

올여름 잘보내세요~~^^'

이 지랄과 같이 되었다. 그렇다 나의 불찰...

그렇게 방법1에서 오토핫키까지 쓰며 고민했던 내용을 고스란히 잊어버리고 같은 실수를 반복했다.

개행문자가 없으면 정상적으로 '날짜','ID','내용'이 저장되겠지만..

개행문자가 있을때는

첫 줄이 작은따옴표를 만나지 못하고 오류, 두번째 줄도 오류.....결과는 두 값 모두 입력안됨

그래서 포기하고 있었는데, 생각해보니 입력받는 내용에

방법2-2) 개행문자를 Replace해주면 되겠네?

하지만 javascript상에서도 \n은 개행문자로 인식한다 → \\n으로 넣으면 비로소 \n으로 텍스트가 저장된다.

추가적으로 ' 문자와 \ 문자는 mysql상에서 인식을 못하니 혹시나 만나게 될 경우 두번 넣어준다.

(\문자는 정규식도 잘 안먹어서 그냥 포기)

            a=msg.replace(/\n/g,'\\n').replace(/\'/g,"\'\'")

'2019-08-05 08:42:53', '아이디', '오늘도 즐거운 하루되세요~\n올여름 잘보내세요~~^^'

이렇게하면 DB엔 완벽히 개행문자로 들어가고 출력도 된다.

하지만 마지막문제, 왜 Web상에서는 개행문자가 적용이 안되고 공백문자로 space로 나올까?

오래지않아 view-source로 그 원인을 알 수 있었다. 진짜 html 소스코드에 개행이 되어 있었다!

오랜 경험으로 html에서 개행문자는 <br></br>임을 알고 있다!

그러면 php 작성을 손봐야 하는구나!

검색어는 php new line to br

http://docs.php.net/manual/kr/function.nl2br.php

 

최종 성공

sql쿼리를 돌려 얻은 값을 nl2br함수로 한번 더 감싸줌

echo nl2br($content);

이제 맘 편히 데이터를 저장할 수 있게 되었다.

더 이상 불편한 행동을 하지 않아도 된다.

너무나도 행복하다.

'Programming > WEBWASDB' 카테고리의 다른 글

Powershell SecureString을 PHP에서 사용하려면  (0) 2020.06.11