修改mongodb3.0副本集使用者密碼遇到的坑

塗宗勳發表於2016-06-16

最近公司對專案安全方面的問題很是重視,進行了多次各種安全漏洞的掃描,於是乎就掃到了mongodb弱口令的問題。

 

在專案部署初期,因為大家對這個都不是特別重視,大概是因為覺得反正是內網專案吧,所以mongodb資料庫的使用者名稱和密碼就都是admin。

 

這次掃到弱口令之後,要求解決這個問題,於是任務便分到了我的頭上。

 

遵循強口令的標準,我把admin改成了由大寫字母、小寫字母、數字和特殊字元共同組成的密碼,但是在更改的過程中卻並不像想象的那麼順利,其中遇到的問題我稱之為mongodb副本集密碼的一些坑。

 

坑在哪裡呢?首先是修改密碼的過程,因為是副本集的緣故,所以理論上是更改資料的時候只需要更改主庫就好,然後從庫就會自動同步。

 

於是我便想到直接更改使用者資訊中的密碼內容,但是密碼資訊是儲存在db.system.users中,這個資料使用者似乎是無權進行更改操作的。

 

雖然之前就知道這個許可權的問題,但是我還是想試一下,畢竟之前我沒有改過副本集的密碼,也不確定究竟可不可行。

 

而嘗試的結果證明這個內容確實是無權修改,我用db.system.users.update更改時,提示許可權不足:

WriteResult({
       "writeError" : {
                "code" : 13,
                "errmsg" : "notauthorized on admin to execute command { update: "system.users",updates: [ { q: { user: "admin" }, u: { $set: { pwd:"123456" } }, multi: false, upsert: false } ], ordered: true}"
       }
})



於是我便想到,不如我把之前的使用者刪掉,然後再重新建立,這樣的話總該沒有問題了吧。但實際上我這樣做的時候,當我刪除了admin使用者之後,再來createUser時,提示我使用者驗證不通過。

 

因為我之前只建立了這一個使用者,因此便只好關閉了程式,然後都以不啟動使用者認證的方式啟動mongodb,之後再次建立使用者,這樣操作之後終於成功換成新的密碼。

 

在此之後,我突然想到是不是可以在兩個使用者的情況下用前邊不成功的方法來修改密碼呢?於是我就做了二次嘗試,建立了兩個使用者。

 

然後我便發現果然如猜測的那樣,當我用某個使用者驗證時,是可以刪除另外一個並再次建立的,這個時候就不會像一個使用者那樣在刪除後重建時,提示驗證問題(當然了使用者角色需要正確的選擇)。

 

鑑於上邊的內容,我想也完全可以有第三種做法,因為我是不改使用者名稱的情況下操作,而如果連使用者名稱和密碼一起改,那麼也就不用如此麻煩了,可以直接建立使用者便好。

 

那麼第二個坑就是,這個密碼中的特殊字元似乎有一定的限制,我在命令列操作時沒有任何問題,但是當我用spring中的程式碼連線時,直接啟動就報錯,提示”&”符有問題。

 

之前的spring連線mongodb的程式碼是這樣:

<mongo:mongo-client replica-set="192.168.91.27:27017" credentials="admin:admin@admin" id="mongo"> 
       <mongo:client-options write-concern="SAFE" connections-per-host="100"
            threads-allowed-to-block-for-connection-multiplier="50"
              /> 
</mongo:mongo-client> 


第二個admin代表密碼,我把這個admin改成新的帶有“&”的密碼(例如“aaa&123$_”)便出了如下問題:

org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import beandefinitions from relative location [spring-mongodb305.xml]
Offending resource: class pathresource [spring.xml]; nested exception is org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 15 in XML document from class path resource[spring-mongodb305.xml] is invalid; nested exception is org.xml.sax.SAXParseException;lineNumber: 15; columnNumber: 102; 在實體引用中, 實體名稱必須緊跟在 `&` 後面。
    atorg.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:70) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:76) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource(DefaultBeanDefinitionDocumentReader.java:274) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseDefaultElement(DefaultBeanDefinitionDocumentReader.java:199) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:184) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:141) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:110) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:508) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:391) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:335) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:303) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:216) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:187) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125) ~[spring-web-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94) ~[spring-web-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:129) ~[spring-context-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:540) ~[spring-context-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:454) ~[spring-context-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:381) ~[spring-web-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:293) ~[spring-web-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106) [spring-web-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4994) [catalina.jar:7.0.57]
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5492) [catalina.jar:7.0.57]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [catalina.jar:7.0.57]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1575) [catalina.jar:7.0.57]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1565) [catalina.jar:7.0.57]
    at java.util.concurrent.FutureTask.run(FutureTask.java:262) [na:1.7.0_79]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_79]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_79]
    at java.lang.Thread.run(Thread.java:745) [na:1.7.0_79]
Caused by: org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 15 in XML document from class path resource[spring-mongodb305.xml] is invalid; nested exception isorg.xml.sax.SAXParseException; lineNumber: 15; columnNumber: 102; 在實體引用中, 實體名稱必須緊跟在 `&` 後面。
    atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:398) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:335) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:303) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource(DefaultBeanDefinitionDocumentReader.java:258) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    ... 28 common frames omitted
Caused by: org.xml.sax.SAXParseException: 在實體引用中, 實體名稱必須緊跟在 `&` 後面。
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198) ~[na:1.7.0_79]
    atcom.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:177) ~[na:1.7.0_79]
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:441) ~[na:1.7.0_79]
    atcom.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:368) ~[na:1.7.0_79]
    atcom.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1436) ~[na:1.7.0_79]
    atcom.sun.org.apache.xerces.internal.impl.XMLScanner.scanAttributeValue(XMLScanner.java:885) ~[na:1.7.0_79]
    atcom.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanAttribute(XMLNSDocumentScannerImpl.java:439) ~[na:1.7.0_79]
    atcom.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:255) ~[na:1.7.0_79]
    atcom.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2786) ~[na:1.7.0_79]
    atcom.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606) ~[na:1.7.0_79]
    atcom.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117) ~[na:1.7.0_79]
    atcom.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510) ~[na:1.7.0_79]
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848) ~[na:1.7.0_79]
    atcom.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777) ~[na:1.7.0_79]
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141) ~[na:1.7.0_79]
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243) ~[na:1.7.0_79]
    atcom.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:347) ~[na:1.7.0_79]
    atorg.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(DefaultDocumentLoader.java:76) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadDocument(XmlBeanDefinitionReader.java:428) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390) ~[spring-beans-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    ...31 common frames omitted



於是我只好把密碼中的”&”去掉,換成其他特殊字元,重新更改了資料庫中的使用者密碼,然後再次啟動時一切便正常了。

 

當然了,這樣改了問題是暫時解決了,專案也正常的執行起來,但是我卻沒有弄明白為什麼要這樣改,於是之後一頓百度後,我發現原來根源的問題並不是mongodb密碼的問題,而是xml的問題。

 

在xml中&有特殊的含義,因此要麼不用,要麼就要使用&amp代替,原來如此,這個坑實際上是因為自己知識瞭解的不夠多以及一時間考慮的問題不夠,而後自己坑了自己。

 

這樣一來也就解釋了我心中的另一個疑惑,那就是為什麼寫在properties中的帶“&”的密碼就沒問題,直接寫在xml中就有問題。


相關文章